﻿#include "LineChartWindow.h"
#include <QDomElement>
#include <QDomDocument>
#include <QDomAttr>
#include <QtGlobal>
#include <set>
#include <complex>

#include "LineChartSidebarSettingsDialog.h"
#include "Curve2DPlotor.h"
#include "TextFileParser.h"
#include "LineChartCoordinateSettingData.h"
#include "LineChartCenterSettingDialog.h"
#include "LineChartTracer.h"
#include "DialogTracer2DSettings.h"
#include "LineChartStraightLine.h"
#include "UnitHelper.h"
#include "BaseModule/IBaseSignal.h"
#include "BaseWidget/IdaDialogMsg.h"
#include "BaseModule/GlobalHelper.h"
#include "BaseWidget/IWidgetSignal.h"
#include "DataManager/WindowTotalData.h"
#include "PostEnumType.h"
#include "vtkTable.h"
#include "DialogAddLocalRange.h"

#include <MainWindowSignalHandler.h>

namespace pst
{
    extern QString g_outputDir;                                                                         // mainWindow中的输出路径
    extern double caculateGraphValueByKey(double key, QSharedPointer<QCPGraphDataContainer> graphData); // mainWindows中的插值计算数据

    LineChartWindow::LineChartWindow(QWidget* parent, int windowId, QList<Info2DPointer>* infoListCopy)
        : Graph2DWindowBase(parent), m_windowId(windowId), m_coodinateSetting(new LineChartCoordinateSettingData(this)), m_centerSettingData(new LineChartCenterSettingData(this))
    {

        m_tracerPropertyWidget = new TracerTableWidget(m_customPlot); // 标记属性窗口
        m_tracerPropertyWidget->installEventFilter(this);             // 标记属性窗口添加事件过滤
        m_measureTableWidget = new MeasureTableWidget(m_customPlot);  // 测量属性窗口
        m_measureTableWidget->installEventFilter(this);               // 测量属性窗口添加事件过滤

        connect(m_tracerPropertyWidget, &TracerTableWidget::signal_removeMarkerSelect, m_customPlot, &Curve2DPlotor::removeMarkerSelect);
        connect(m_tracerPropertyWidget, &TracerTableWidget::signal_removeMarkerAll, m_customPlot, &Curve2DPlotor::removeMarkerAll);
        connect(m_tracerPropertyWidget, &TracerTableWidget::signal_disableTracer, m_customPlot, &Curve2DPlotor::disableTracer);
        connect(m_tracerPropertyWidget, &TracerTableWidget::signal_enableTracer, m_customPlot, &Curve2DPlotor::enableTracer);
        

        /*
         * 修改初始化的配置值
         */
        Style2D_AxisRange* style2D_AxisRangeX = new Style2D_AxisRange;
        style2D_AxisRangeX->m_customStepSize = 2;
        m_coodinateSetting->setXAxisRange(style2D_AxisRangeX);

        Style2D_AxisRange* style2D_AxisRangeY = new Style2D_AxisRange;
        style2D_AxisRangeY->m_customStepSize = 2;
        m_coodinateSetting->setYAxisRange(style2D_AxisRangeY);

        m_centerSettingData->m_lineChartCoordinateSettingData = m_coodinateSetting;
        // 坐标系初始化
        initCoordinateSystem();

        m_settings = new LineChartSidebarSettingsDialog(this); // 右侧属性栏
        m_settings->setWindowId(m_windowId);
        // 先连接信号和槽，然后设置m_settings的数值，以使其直接作用到m_customPlot
        initConnections();

        m_settings->updateUILayout(); // 布局
        m_settings->setInfoMap(&m_curveMap); 
        /// @brief 测试代码结束

        // QSplitter* splitter = new QSplitter(Qt::Horizontal, this);
        // splitter->addWidget(m_customPlot);
        // splitter->addWidget(m_settings);
        // splitter->setSizes({3000, 1000});
        QHBoxLayout* layout = new QHBoxLayout(this);
        layout->setContentsMargins(0, 0, 0, 0);
        layout->addWidget(m_customPlot);
        layout->addWidget(m_settings);
        layout->setStretch(0, 1);
        layout->setStretch(1, 0);
        // layout->addWidget(splitter);
        //  try
        //{
        // QString str = "self+2%*(5+6)/((-1+2*-3*Average(3*4^-4+-5,max(3*min(5,6)*(5*(4-1)+6))*5)-6^(3^-2))-6)/-5";
        //  QString str = "self--2*(1+-2*3^-3*-4--2)/-5";
        // }
        //  catch (int msg)
        //{
        //     qDebug() << "catch: " << msg;
        // }
        // 设置
        m_customPlot->setInfoListCopy(infoListCopy);
        m_customPlot->legend->setFillOrder(QCPLayoutGrid::foRowsFirst);
        m_customPlot->legend->setWrap(34);

        m_customPlot->xAxis->setNumberFormat("f");
        m_customPlot->xAxis->setNumberPrecision(6);
        m_customPlot->yAxis->setNumberFormat("f");
        m_customPlot->yAxis->setNumberPrecision(6);
        /*
         * m_customPlot信号导出marker数据
         */
        connect(m_customPlot, &Curve2DPlotor::signal_exportMarkerData, m_tracerPropertyWidget, &TracerTableWidget::exportDatas);
        connect(m_customPlot, &QCustomPlot::afterLayout, this, &LineChartWindow::adjustLegendColumns);

        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartDialogInterpolation, this, [this](int number, int type)
            { 
                if(!this->isVisible()) return;
                InterpolationType interpolationType = static_cast<InterpolationType>(type);
                slot_interpolationData(number, interpolationType);
            });
        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartDialogTransferFunction, this, [this](QString graphName, QString calibrationGraphName, QString type)
                { 
                if(!this->isVisible()) return;
                slot_computeTransferFunction(graphName, calibrationGraphName, type); 
            });
        
        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartDialogIPLCalculation, this, [this](QString IPLString)
            { 
                if(!this->isVisible()) return;
                QList<QString> IPLList = IPLString.split(",");
                QList<QVariant> IPLDatas;

                for (QString data : IPLList)
                {
                    if (data.startsWith("DDOUBLE:"))
                    {
                        IPLDatas.append(data.mid(8).toDouble());
                    }
                    else if (data.startsWith("SSTRING:"))
                    {
                        IPLDatas.append(data.mid(8));
                    }
                }
                bool _success = true;
                slot_computeIPL(IPLDatas,&_success); 
            });

        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartDialogWaveformAnalysis, this, [this](QString graphName, double cutOffFrequency, QString filterType, int filterOrder, double leftBoundary, double rightBoundary, int windowId, QString resultList, bool isPythonRun)
            { 
                if(!this->isVisible()) return;
                slot_computeWaveformAnalysis(graphName, cutOffFrequency, filterType, filterOrder, leftBoundary, rightBoundary, windowId, resultList, isPythonRun);
            });
        //connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartDialogWaveformAnalysis, this, &LineChartWindow::slot_computeWaveformAnalysis);
        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartDialogCurveSmoothing, this, [this](double range)
            { 
                if(!this->isVisible()) return;
                emit slot_smoothData(range);
            });

        
        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartCenterWidgetDialogAddLocalRange, this, [this](double rangeLower, double rangeUpper, QString selectNames, bool execFlag, bool edit)
                { 
                if(!this->isVisible()) return;
                QList<QString> selectNamesList = selectNames.split(",");
                slot_localScope(rangeLower, rangeUpper, selectNamesList, execFlag, edit);
            });

        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartSidebarSettingsRenameCheck, this, [this](QString text)
            { 
                if(!this->isVisible()) return;
                auto listView = m_settings->getCurveNameListView();
                QModelIndexList selectedIndexes = listView->selectionModel()->selectedIndexes();
                if (selectedIndexes.size() != 1)
                {
                    return;
                }
                auto model = (QStandardItemModel*)listView->model();
                auto item = model->itemFromIndex(selectedIndexes.first());

                item->setText(text);
                slot_renameCheck();
            });


        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartWindowChangeTracerProperty, this, [this](
            int tracerID,
            QString tracerName,
            double x,
            int symbolStyle,
            double symbolSize,
            QString symbolColor
        ){ 
            if(!this->isVisible()) return;
            Style2D_TracerProperty* tmp = nullptr;
            for (int i = 0; i < m_tracerPropertyWidget->rowCount(); ++i)
            {
                auto tracer = m_tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (tracer->getTracerIndex() == tracerID)
                {
                    tmp = tracer->getStyle2DTracerProperty();
                    if (tmp == nullptr)
                        return;
                    tracer->SetName(tracerName);
                    tracer->setGraphKey(x);
                    tracer->setStyle(QCPItemTracer::TracerStyle(symbolStyle + 1));
                    tracer->setSize(symbolSize * 2);
                    tracer->setPen(QPen(QColor('#'+symbolColor)));

                    tmp->m_x = x;
                    tmp->m_tracerName = tracerName;
                    tmp->m_symbolStyle = QCPItemTracer::TracerStyle(symbolStyle + 1);
                    tmp->m_symbolSize = symbolSize * 2;
                    tmp->m_symbolColor = QColor('#' + symbolColor);

                    tracer->setStyle2DTracerProperty(tmp);
                    break;
                }
            }

            m_customPlot->replot();
        });

        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartWindowChangeGuideLineProperty, this, [this](int guideLineID, double value, int guideLineStyle, double guideLineThickness, QString guideLineColor)
            {
            if (!this->isVisible())
                return;

            auto _tempGuideLine = m_customPlot->getLineChartStraightLineByID(guideLineID);
            auto tmp = _tempGuideLine->getStyle2DGuideLineProperty();
            if (_tempGuideLine == nullptr || tmp == nullptr)
            {
                return;
            }

            _tempGuideLine->SetValue(value);
            auto penLine = _tempGuideLine->pen();
            penLine.setStyle(Qt::PenStyle(guideLineStyle + 1));
            penLine.setWidthF(guideLineThickness);
            penLine.setColor(QColor('#'+ guideLineColor));
            _tempGuideLine->setPen(penLine);

            m_customPlot->replot(); 
        });

        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartChangeLineProperty, this, [this](int windowUniversalID, int curveInfoID, QString docStr)
        { 
            if(!this->isVisible()) return;

            LineChartCenterSettingData* tmp = nullptr;
            LineChartCenterSettingData* dataGraph2DSettings = nullptr;
            if (curveInfoID != -1)
            {
                auto _curveInfo = WindowTotalDataInstance->getInfomationCurve2DBasicalByID(curveInfoID);
                dataGraph2DSettings = _curveInfo->getLineChartCenterSettingData();
                if (dataGraph2DSettings == nullptr)
                    return;
                tmp = dataGraph2DSettings;
            }
            else
            {
                auto _lineChartWindow = (LineChartWindow*)WindowTotalDataInstance->getGraph2DWindowByID(windowUniversalID);
                dataGraph2DSettings = _lineChartWindow->getLineChartCenterSettingData();
                if (dataGraph2DSettings == nullptr)
                    return;
                tmp = dataGraph2DSettings;
            }

            QDomDocument* doc = new QDomDocument("docStr");
            doc->setContent(docStr);

            QDomElement lineChartCoordinateSettingDataElement = doc->elementsByTagName("LineChartCoordinateSettingData").at(0).toElement();
            auto style2D_DataPropertyElement = doc->elementsByTagName("Style2D_DataProperty");

            tmp->m_lineChartCoordinateSettingData->readFromProjectFile(&lineChartCoordinateSettingDataElement);
            if (!style2D_DataPropertyElement.isEmpty())
            {
                tmp->m_style2D_DataProperty->readFromProjectFile(&style2D_DataPropertyElement.at(0).toElement(), false);
            }
            slot_ChangeLineProperty(windowUniversalID, curveInfoID);

        });

        connect(IBaseSignalInstance, &BaseWidget::IWidgetSignal::signal_lineChartWindowSetIsEdit, this, [this](bool state)
        { 
            if(!this->isVisible()) return;
            this->setIsEdit(state);
        });

    }

    LineChartWindow::~LineChartWindow()
    {
    }

    void LineChartWindow::adjustLegendColumns()
    {
        if (!m_customPlot->legend->visible())
        {
            return;
        }

        auto legend = m_customPlot->legend;
        QFontMetrics fm(legend->font());
        auto iconSize = legend->iconSize();
        // 让图标高度也达到文字高度
        legend->setIconSize(QSize(fm.height() * 32. / 18. * 1.3, fm.height() * 1.3));
        int rowSpacing = legend->rowSpacing();           // 行间距
        int itemHeight = qMax(iconSize.height(), fm.height()) + rowSpacing /*+ iconPad*/;
        int availH = m_customPlot->axisRect()->rect().height() - 30;
        int maxPerCol = qMax(1, availH / itemHeight);

        legend->setFillOrder(QCPLegend::foRowsFirst);
        legend->setWrap(maxPerCol);
        m_customPlot->replot();
    }

    void LineChartWindow::addGraph2D(Info2DPointer& info)
    {
        QString name = info->getCurveName().remove(QRegularExpression("\\[.*?]$"));

        if (name.isEmpty())
        {
            name = "曲线";
        }
        QString incrementName = autoIncrementName(name);
        //QString name = "曲线_" + QString::number(++m_graphIndex);
        info->setCurveName(incrementName);
        addNewGraph(info);
        slot_updateName();
        m_addCurveInfo.append(info);
        QCoreApplication::processEvents(); // 让 UI 有机会更新,防止获取高度axisRect()->rect().height()失败
        QTimer::singleShot(0, this, [=]() {
            adjustLegendColumns();
            });
    }
    void LineChartWindow::setWindowID(int windowID)
    {
        m_windowId = windowID;
    }
    int LineChartWindow::getWindowID() const
    {
        return m_windowId;
    }

    void LineChartWindow::setWindowUniversalID(int windowUniversalID)
    {
        m_windowUniversalID = windowUniversalID;
        m_settings->setWindowUniversalID(windowUniversalID);
    }
    int LineChartWindow::getWindowUniversalID() const
    {
        return m_windowUniversalID;
    }

    QDomElement& LineChartWindow::writeToProjectFile(QDomDocument* doc, QDomElement* element, bool isdiso)
    {
        QDomElement _LineChartWindowDataRoot = doc->createElement("GraphWindow");
        QDomAttr _WindowUniversalIDattr = doc->createAttribute("WindowUniversalID");
        _WindowUniversalIDattr.setValue(QString::number(m_windowUniversalID));
        _LineChartWindowDataRoot.setAttributeNode(_WindowUniversalIDattr);
        QDomAttr _idattr = doc->createAttribute("WindowID");
        _idattr.setValue(QString::number(m_windowId));
        _LineChartWindowDataRoot.setAttributeNode(_idattr);
        QDomAttr typeattr = doc->createAttribute("WindowType");
        typeattr.setValue("LineChartWindow");
        _LineChartWindowDataRoot.setAttributeNode(typeattr);

        // GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "Name", QString("m_name"));
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "AutoXRescaleAxes", QString::number(m_autoXRescaleAxes));
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "AutoYRescaleAxes", QString::number(m_autoYRescaleAxes));
        QString _xAxisRangeStr = QString("%1,%2").arg(m_xAxisRange.lower).arg(m_xAxisRange.upper);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "XAxisRange", _xAxisRangeStr);
        QString _yAxisRangeStr = QString("%1,%2").arg(m_yAxisRange.lower).arg(m_yAxisRange.upper);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "YAxisRange", _yAxisRangeStr);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "TracerIndex", QString::number(m_tracerIndex));
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "Unit", m_unit);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "YUnit", m_yUnit);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "GraphIndex", QString::number(m_graphIndex));
        auto _standardCcurveNumberStr = GlobalHelperInstance->convertQHashQStringIntToQString(m_standardCcurveNumber);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "StandardCcurveNumber", _standardCcurveNumberStr);
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "HirfNumber", QString::number(m_hirfNumber));
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "EffectivenessNumber", QString::number(m_effectivenessNumber));
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "AutoXTitleText", QString::number(m_autoXTitleText));
        GlobalHelperInstance->createDomElement(doc, &_LineChartWindowDataRoot, "AutoYTitleText", QString::number(m_autoYTitleText));

        element->appendChild(_LineChartWindowDataRoot);

        if (m_coodinateSetting != nullptr)
            m_coodinateSetting->writeToProjectFile(doc, &_LineChartWindowDataRoot, isdiso);
        // m_curveMap存了所有曲线
        for (auto _curveInfoPair : m_curveMap)
        {
            auto _item = _curveInfoPair.first;
            auto params = _item->data(Qt::UserRole + 3).toString();
            _curveInfoPair.second->setIsCurveVisible(_item->checkState());
            _curveInfoPair.second->setLineChartCurveEditParameters(params);
            _curveInfoPair.second->writeToProjectFile(doc, &_LineChartWindowDataRoot, GraphType::TwoDLineChart, isdiso);
        }
        if (m_tracerPropertyWidget != nullptr)
            m_tracerPropertyWidget->writeToProjectFile(doc, &_LineChartWindowDataRoot, GraphType::TwoDLineChart, isdiso);
        if (m_measureTableWidget != nullptr)
            m_measureTableWidget->writeToProjectFile(doc, &_LineChartWindowDataRoot, isdiso);
        m_customPlot->writeToProjectFile(doc, &_LineChartWindowDataRoot, isdiso);

        return _LineChartWindowDataRoot;
    }

    void LineChartWindow::readFromProjectFile(QDomElement* element, bool isdiso)
    {
        m_windowUniversalID = element->attribute("WindowUniversalID").toInt();
        int id = element->attribute("WindowID").toInt();
        m_windowId = id;

        QDomNodeList AutoXRescaleAxesList = element->elementsByTagName("AutoXRescaleAxes");
        m_autoXRescaleAxes = (bool)AutoXRescaleAxesList.at(0).toElement().text().toInt();
        QDomNodeList AutoYRescaleAxesList = element->elementsByTagName("AutoYRescaleAxes");
        m_autoYRescaleAxes = (bool)AutoYRescaleAxesList.at(0).toElement().text().toInt();
        QDomNodeList XAxisRangeList = element->elementsByTagName("XAxisRange");
        QString XAxisRangeStr = XAxisRangeList.at(0).toElement().text();
        m_xAxisRange.lower = XAxisRangeStr.split(",")[0].toDouble();
        m_xAxisRange.upper = XAxisRangeStr.split(",")[1].toDouble();
        QDomNodeList YAxisRangeList = element->elementsByTagName("YAxisRange");
        QString YAxisRangeStr = YAxisRangeList.at(0).toElement().text();
        m_yAxisRange.lower = YAxisRangeStr.split(",")[0].toDouble();
        m_yAxisRange.upper = YAxisRangeStr.split(",")[1].toDouble();
        QDomNodeList TracerIndexList = element->elementsByTagName("TracerIndex");
        m_tracerIndex = TracerIndexList.at(0).toElement().text().toInt();
        QDomNodeList UnitList = element->elementsByTagName("Unit");
        m_unit = UnitList.at(0).toElement().text();
        QDomNodeList YUnitList = element->elementsByTagName("YUnit");
        m_yUnit = YUnitList.at(0).toElement().text();
        QDomNodeList GraphIndexList = element->elementsByTagName("GraphIndex");
        m_graphIndex = GraphIndexList.at(0).toElement().text().toInt();
        QDomNodeList StandardCcurveNumberList = element->elementsByTagName("StandardCcurveNumber");
        auto _StandardCcurveNumberStr = StandardCcurveNumberList.at(0).toElement().text();
        m_standardCcurveNumber = GlobalHelperInstance->convertQStringToQHashQStringInt(_StandardCcurveNumberStr);
        QDomNodeList HirfNumberList = element->elementsByTagName("HirfNumber");
        m_hirfNumber = HirfNumberList.at(0).toElement().text().toInt();
        QDomNodeList EffectivenessNumberList = element->elementsByTagName("EffectivenessNumber");
        m_effectivenessNumber = EffectivenessNumberList.at(0).toElement().text().toInt();
        QDomNodeList AutoXTitleTextList = element->elementsByTagName("AutoXTitleText");
        m_autoXTitleText = (bool)AutoXTitleTextList.at(0).toElement().text().toInt();
        QDomNodeList AutoYTitleTextList = element->elementsByTagName("AutoYTitleText");
        m_autoYTitleText = (bool)AutoYTitleTextList.at(0).toElement().text().toInt();

        auto _centerSettingNodeList = element->elementsByTagName("LineChartCoordinateSettingData");
        m_coodinateSetting->readFromProjectFile(&_centerSettingNodeList.at(0).toElement(), isdiso);
        m_centerSettingData->m_lineChartCoordinateSettingData = m_coodinateSetting;

        auto _infosNodeList = element->elementsByTagName("InfomationCurve2DBasical");
        auto _infosCount = _infosNodeList.count();
        if (_infosCount == 0)
            return;
        for (int i = 0; i < _infosCount; i++)
        {
            auto _info = Info2DPointer::create();
            _info->readFromProjectFile(&_infosNodeList.at(i).toElement(), GraphType::TwoDLineChart, isdiso);
            if (_info->getProjectTreeSourceItem() == nullptr)
                continue;
            m_centerSettingData->m_style2D_DataProperty = _info->getCurvePropertyData();
            _info->setLineChartCenterSettingData(m_centerSettingData);
            m_addCurveInfo.append(_info);
            addNewGraphByOpenProject(_info, _info->getLineChartCurveEditParameters());

            //更新侧边栏和曲线数据
            auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
            auto _curveSiderBarItem = this->getItemFromCurveInfo(_info);
            if (_curveSiderBarItem != nullptr)
            {
                auto _itemIndex = model->indexFromItem(_curveSiderBarItem);
                emit IBaseSignalInstance->signal_lineChartSidebarCurveNameClicked(m_windowId, { _itemIndex.row() });
                if (_info->getIsNormalized() || _info->getIsDB() || _info->getIsMathematicalOperations())
                    emit IBaseSignalInstance->signal_lineChartSidebarDataOperationChanged(m_windowId, _info->getIsNormalized(), _info->getIsDB(), _info->getIsMathematicalOperations());
            }
            slot_ChangeLineProperty(m_windowUniversalID, _info->getInformationID(),_info, false);
        }
        auto _TracerTableWidgetNodeList = element->elementsByTagName("TracerTableWidget");
        m_tracerPropertyWidget->readFromProjectFile(&_TracerTableWidgetNodeList, m_customPlot, GraphType::TwoDLineChart, isdiso);
        if (m_tracerPropertyWidget->rowCount() > 0)
        {
            if (m_tracerPropertyWidget->isHidden())
            {
                QPoint p(0, 0);
                if (!m_measureTableWidget->isHidden() && m_measureTableWidget->geometry().x() < m_customPlot->axisRect()->topLeft().x() + 20)
                {
                    p.setX(m_measureTableWidget->width() + 10);
                }
                m_tracerPropertyWidget->move(m_customPlot->axisRect()->topLeft() + p + QPoint(10, 10));
                m_tracerPropertyWidget->show();
            }
        }
        auto _MeasureTableWidgetNodeList = element->elementsByTagName("MeasureTableWidget");
        m_measureTableWidget->readFromProjectFile(&_MeasureTableWidgetNodeList, m_customPlot, isdiso);
        if (m_measureTableWidget->rowCount() > 0)
        {
            if (m_measureTableWidget->isHidden())
            {
                QPoint p(0, 0);
                if (!m_tracerPropertyWidget->isHidden() && m_tracerPropertyWidget->geometry().x() < m_customPlot->axisRect()->topLeft().x() + 20)
                {
                    p.setX(m_tracerPropertyWidget->width() + 10);
                }
                m_measureTableWidget->move(m_customPlot->axisRect()->topLeft() + p + QPoint(10, 10));
                m_measureTableWidget->show();
            }
        }
        //最后刷新标记的显示隐藏
        for (auto curvePair : m_curveMap)
        {
            auto _checkState = curvePair.second->getIsCurveVisible();
            if (!_checkState) // 默认可见，则不用设置
            {
                auto _curveSiderBarItem = getItemFromCurveInfo(curvePair.second);
                _curveSiderBarItem->model()->blockSignals(true);
                _curveSiderBarItem->setData(_checkState, Qt::UserRole);
                _curveSiderBarItem->model()->blockSignals(false);
                _curveSiderBarItem->setCheckState((Qt::CheckState)_checkState);
                slot_showHideItemActor(_curveSiderBarItem);
            }
        }
        m_customPlot->readFromProjectFile(&element->elementsByTagName("Curve2DPlotor").at(0).toElement(), isdiso);
    }

    void LineChartWindow::slot_adaptiveRange()
    {
        // 先刷新一次
        m_customPlot->replot();

        auto m_tracerList = getAllTracers(this->m_customPlot); // 获取所有标记
        if (m_autoXRescaleAxes)
        {
            m_customPlot->xAxis->rescale(true);
            QCPRange xr = m_customPlot->xAxis->range();
            for (LineChartTracer* tracer : m_tracerList)
            {
                if (tracer == nullptr)
                    continue;
                // tracer->GetOnlyShowTracer()==true为预览标记
                if (tracer->visible() == false || tracer->GetOnlyShowTracer() == true)
                    continue;
                tracer->updatePosition(); // 确保 position 是最新的
                auto label = tracer->GetLabel();
                double leftPixelX = label->left->pixelPosition().x() - 10;
                double leftTx = label->position->keyAxis()->pixelToCoord(leftPixelX);
                double rightPixelX = label->right->pixelPosition().x() + 10;
                double rightTx = label->position->keyAxis()->pixelToCoord(rightPixelX);
                xr.lower = qMin(xr.lower, leftTx);
                xr.upper = qMax(xr.upper, rightTx);
                m_customPlot->xAxis->setRange(xr);
            }
        }
        else
        {
            m_customPlot->xAxis->setRange(m_xAxisRange);
        }

        if (m_autoYRescaleAxes)
        {
            m_customPlot->yAxis->rescale(true);
            QCPRange yr = m_customPlot->yAxis->range();
            for (LineChartTracer* tracer : m_tracerList)
            {
                if (tracer == nullptr)
                    continue;
                // tracer->GetOnlyShowTracer()==true为预览标记
                if (tracer->visible() == false || tracer->GetOnlyShowTracer() == true)
                    continue;
                tracer->updatePosition(); // 确保 position 是最新的
                double bottomPixelY = tracer->position->pixelPosition().y() + 8;
                double by = tracer->position->valueAxis()->pixelToCoord(bottomPixelY);
                auto label = tracer->GetLabel();
                double topPixelY = label->top->pixelPosition().y() - 10;
                double ty = label->position->valueAxis()->pixelToCoord(topPixelY);
                yr.lower = qMin(yr.lower, by);
                yr.upper = qMax(yr.upper, ty);
                m_customPlot->yAxis->setRange(yr);
            }
        }
        else
        {
            m_customPlot->yAxis->setRange(m_yAxisRange);
        }
        m_customPlot->replot();
    }

    // 设置框中选中的曲线发生改变->根据曲线信息更新m_settings
    void LineChartWindow::slot_chosenItemsChanged(const QList<QStandardItem*>& itemList)
    {
        QList<Info2DPointer> curInfoList;
        for (const auto& i : itemList)
        {
            if (!judgmentItemInfoPairIsExist(i))
            {
                // todo 警告
                continue;
            }
            curInfoList.append(getCurveInfoByItem(i));
        }

        if (curInfoList.isEmpty())
        {
            // 折叠控制面板
            m_settings->hideCurvePropertylPanel();
        }
        else
        {
            // 各个曲线信息的交集
            Info2DPointer commonInfo = Info2DPointer::create();
            auto isSuc = InfomationCurve2DBasical::getCommonData(curInfoList, commonInfo);
            if (!isSuc)
            {
                // TODO 警告
                return;
            }
            m_settings->setCurvePropertyPanelState(commonInfo);
        }

        // 选中状态
        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        for (auto row = 0; row < model->rowCount(); row++)
        {
            QStandardItem* item = model->item(row);

            QCPGraph* graph = qobject_cast<QCPGraph*>(getCurveInfoByItem(item)->getCurveLineAddress());
            QModelIndex index = model->indexFromItem(item);
            auto isChecked = selectionModel->isSelected(index);

            QCPPlottableLegendItem* legendItem = m_customPlot->legend->itemWithPlottable(graph);
            legendItem->setSelected(isChecked);
            if (isChecked)
            {
                graph->setSelection(QCPDataSelection(graph->data()->dataRange()));
            }
            else
            {
                QCPDataSelection s;
                graph->setSelection(s);
            }
        }
        m_customPlot->replot();
        slot_updateSelectedGraphState();
    }

    void LineChartWindow::slot_LinePropertyShow(QCPGraph* plottable, int index)
    {
        // LineChartCenterSettingData* tmp = new LineChartCenterSettingData(this);

        //// x
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_isAutoName = this->GetXTitleAutoFlag();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleText = m_customPlot->xAxis->label().remove(QRegularExpression("\\[.+]"));
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_xUnitType = m_xAxisUnitType;
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_xAxisUnit = m_xAxisUnit;
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleFontColor = m_customPlot->xAxis->labelColor();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleFontSize = m_customPlot->xAxis->labelFont().pointSize();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisColor = m_customPlot->xAxis->basePen().color();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisThickness = m_customPlot->xAxis->basePen().widthF();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_valuePrecision = m_customPlot->xAxis->numberPrecision();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisDigitColor = m_customPlot->xAxis->tickLabelColor();
        // tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisDigitSize = m_customPlot->xAxis->tickLabelFont().pointSize();

        //// xRange
        // tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoRange = this->GetXAutoFlag();
        // if (tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoRange)
        //{
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_maxValue = m_customPlot->xAxis->range().upper;
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_minValue = m_customPlot->xAxis->range().lower;
        // }
        // else
        //{
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_maxValue = m_xAxisRange.upper;
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_minValue = m_xAxisRange.lower;
        // }
        // auto tickerX = dynamic_cast<QCPAxisTickerFixed*>(m_customPlot->xAxis->ticker().data());
        // if (tickerX == nullptr)
        //{
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoStepSize = true;
        // }
        // else
        //{
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoStepSize = false;
        //     tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_customStepSize = tickerX->tickStep();
        // }

        //// y
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_isAutoName = this->GetYTitleAutoFlag();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleText = m_customPlot->yAxis->label().remove(QRegularExpression("\\[.+]"));
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_yAxisUnitList = m_yAxisUnitList;
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleFontColor = m_customPlot->yAxis->labelColor();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleFontSize = m_customPlot->yAxis->labelFont().pointSize();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisColor = m_customPlot->yAxis->basePen().color();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisThickness = m_customPlot->yAxis->basePen().widthF();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_valuePrecision = m_customPlot->yAxis->numberPrecision();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisDigitColor = m_customPlot->yAxis->tickLabelColor();
        // tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisDigitSize = m_customPlot->yAxis->tickLabelFont().pointSize();

        //// yRange
        // tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoRange = this->GetYAutoFlag();
        // if (tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoRange)
        //{
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_maxValue = m_customPlot->yAxis->range().upper;
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_minValue = m_customPlot->yAxis->range().lower;
        // }
        // else
        //{
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_maxValue = m_yAxisRange.upper;
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_minValue = m_yAxisRange.lower;
        // }
        // auto tickerY = dynamic_cast<QCPAxisTickerFixed*>(m_customPlot->yAxis->ticker().data());
        // if (tickerY == nullptr)
        //{
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoStepSize = true;
        // }
        // else
        //{
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoStepSize = false;
        //     tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_customStepSize = tickerY->tickStep();
        // }

        //// grid
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_isMainGridLineDisplay = m_customPlot->xAxis->grid()->visible();
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_mainGridLineColor = m_customPlot->xAxis->grid()->pen().color();
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_mainGridLineStyle = m_customPlot->xAxis->grid()->pen().style() - 1;
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_mainGridLineThickness = m_customPlot->xAxis->grid()->pen().widthF();
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_isSecondaryGridLineDisplay = m_customPlot->xAxis->grid()->subGridVisible();
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_secondaryGridLineColor = m_customPlot->xAxis->grid()->subGridPen().color();
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_secondaryGridLineStyle = m_customPlot->xAxis->grid()->subGridPen().style() - 1;
        // tmp->m_lineChartCoordinateSettingData->getGrid()->m_secondaryGridLineThickness = m_customPlot->xAxis->grid()->subGridPen().widthF();

        //// title
        // auto title = qobject_cast<QCPTextElement*>(m_customPlot->plotLayout()->element(0, 0));
        // if (title != nullptr)
        //{
        //     tmp->m_lineChartCoordinateSettingData->getTitle()->m_titleName = title->text();
        //     tmp->m_lineChartCoordinateSettingData->getTitle()->m_titleFontColor = title->textColor();
        //     tmp->m_lineChartCoordinateSettingData->getTitle()->m_titleFontSize = title->font().pointSize();
        // }

        //// legned
        // tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendFontColor = m_customPlot->legend->textColor();
        // tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendFontSize = m_customPlot->legend->font().pointSize();
        // tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendLineColor = m_customPlot->legend->borderPen().color();
        // tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendLineThickness = m_customPlot->legend->borderPen().widthF();

        // if (plottable != nullptr)
        //{
        //     // data
        //     tmp->m_style2D_DataProperty->m_resultDataName = plottable->name();
        //     tmp->m_style2D_DataProperty->m_dataLineColor = plottable->pen().color();
        //     tmp->m_style2D_DataProperty->m_dataLineStyle = plottable->pen().style() - 1;
        //     tmp->m_style2D_DataProperty->m_dataLineThickness = plottable->pen().widthF();
        //     tmp->m_style2D_DataProperty->m_isDisplaySymbol = !plottable->scatterStyle().isNone();
        //     tmp->m_style2D_DataProperty->m_symbolStyle = plottable->scatterStyle().shape() - 1;
        //     tmp->m_style2D_DataProperty->m_symbolSize = plottable->scatterStyle().size() / 2;
        //     tmp->m_style2D_DataProperty->m_symbolColor = plottable->scatterStyle().pen().color();
        // }
        // else
        //{
        //     m_doubleClickPlottable = nullptr;
        // }

        emit IWidgetSignalInstance->signal_exitAddMarkerState();

        if (plottable != nullptr)
        {
            for (auto i : m_addCurveInfo)
            {
                if (plottable == i->getCurveLineAddress())
                {
                    m_centerSettingData->m_style2D_DataProperty = i->getCurvePropertyData();
                    break;
                }
            }
        }
        else
        {
            m_doubleClickPlottable = nullptr;
            m_centerSettingData->m_style2D_DataProperty = nullptr;
        }
        auto _x = m_centerSettingData->m_lineChartCoordinateSettingData;
        auto _dialog = new LineChartCenterSettingDialog(this);
        if (nullptr != m_doubleClickPlottable && m_graphs.contains(m_doubleClickPlottable))
        {
            for (auto _curvePair : m_curveMap)
            {
                if (_curvePair.second->getCurveLineAddress() == m_doubleClickPlottable)
                {
                    _dialog->setCurveInfoID(_curvePair.second->getInformationID());
                    break;
                }
            }
            _dialog->setIndexOfGraph(m_graphs.indexOf(m_doubleClickPlottable));
        }
        _dialog->setWindowUniversalID(m_windowUniversalID);
        // connect(_dialog, &LineChartCenterSettingDialog::pyScriptIsRunning, m_settings, &Graph2DSettings::setScriptRuning);
        //connect(_dialog, &LineChartCenterSettingDialog::SignalSendData, this, &LineChartWindow::slot_ChangeLineProperty);
        connect(_dialog, &LineChartCenterSettingDialog::SignalSendData, [=](int windowUniversalID, int curveInfoID, Info2DPointer info)
            { 

                LineChartCenterSettingData* tmp = nullptr;
                LineChartCenterSettingData* dataGraph2DSettings = nullptr;
                if (curveInfoID != -1)
                {
                    auto _curveInfo = WindowTotalDataInstance->getInfomationCurve2DBasicalByID(curveInfoID);
                    dataGraph2DSettings = _curveInfo->getLineChartCenterSettingData();
                    if (dataGraph2DSettings == nullptr)
                        return;
                    tmp = dataGraph2DSettings;
                }
                else
                {
                    auto _lineChartWindow = (LineChartWindow*)WindowTotalDataInstance->getGraph2DWindowByID(windowUniversalID);
                    dataGraph2DSettings = _lineChartWindow->getLineChartCenterSettingData();
                    if (dataGraph2DSettings == nullptr)
                        return;
                    tmp = dataGraph2DSettings;
                }

                QDomDocument* doc = new QDomDocument();
                QDomElement element = doc->createElement("tmp_root");
                doc->appendChild(element);
                QDomElement lineChartCoordinateSettingDataElement = tmp->m_lineChartCoordinateSettingData->writeToProjectFile(doc, &element);
                if (tmp->m_style2D_DataProperty)
                {
                    QDomElement style2D_DataPropertyElement = tmp->m_style2D_DataProperty->writeToProjectFile(doc, &element, false);
                }
                QString docStr = doc->toString();

                QString _pyCode = QString("PostProcessing.lineChartChangeLineProperty(%1,%2,'''%3''')")
                                      .arg(windowUniversalID)
                                      .arg(curveInfoID)
                                      .arg(docStr)
                                      .remove(QRegExp("[\r\n]"));
                emit IBaseSignalInstance->signal_execPYCode(QStringList{_pyCode}, true, false);


                slot_ChangeLineProperty(windowUniversalID, curveInfoID, info);
                m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_minValue = m_customPlot->xAxis->range().lower;
                m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_maxValue = m_customPlot->xAxis->range().upper;
                m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_minValue = m_customPlot->yAxis->range().lower;
                m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_maxValue = m_customPlot->yAxis->range().upper;

                auto xTickVec = m_customPlot->xAxis->tickVectorLabels();
                auto yTickVec = m_customPlot->yAxis->tickVectorLabels();
                if (xTickVec.size() > 1)
                {
                    m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_customStepSize = std::abs(xTickVec[0].toDouble()- xTickVec[1].toDouble());
                }
                if (yTickVec.size() > 1)
                {
                    m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_customStepSize = std::abs(yTickVec[0].toDouble() - yTickVec[1].toDouble());
                }

                _dialog->InitData(m_centerSettingData);
            });
        connect(_dialog, &LineChartCenterSettingDialog::signal_checkCurveNameExist, this, &LineChartWindow::slot_checkCurveNameExist);

        auto xTickVec = m_customPlot->xAxis->tickVectorLabels();
        auto yTickVec = m_customPlot->yAxis->tickVectorLabels();
        if (xTickVec.size() > 1)
        {
            m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_customStepSize = std::abs(xTickVec[0].toDouble() - xTickVec[1].toDouble());
        }
        if (yTickVec.size() > 1)
        {
            m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_customStepSize = std::abs(yTickVec[0].toDouble() - yTickVec[1].toDouble());
        }
        _dialog->InitData(m_centerSettingData);
        _dialog->ChangeCurrentWidget(index);
        _dialog->showWindow();
    }

    void LineChartWindow::slot_checkCurveNameExist(QString newCurveName, bool &exist)
    {
        auto listView = m_settings->getCurveNameListView();
        QModelIndexList selectedIndexes = listView->selectionModel()->selectedIndexes();
        if (selectedIndexes.size() != 1)
        {
            exist = false;
            return;
        }

        auto model = (QStandardItemModel*)listView->model();
        auto item = model->itemFromIndex(selectedIndexes.first());
        for (auto curvePair : m_curveMap)
        {
            auto tmpItem = curvePair.first;
            if (tmpItem != item)
            {
                if (newCurveName == tmpItem->text())
                {
                    exist = true;
                    return;
                }
            }

        }
    }

    void LineChartWindow::slot_ChangeLineProperty(int windowUniversalID, int curveInfoID, Info2DPointer info, bool bCheckName)

    {
        LineChartCenterSettingData* tmp = nullptr; 
        LineChartCenterSettingData* dataGraph2DSettings = nullptr; 
        if (curveInfoID != -1)
        {
            auto _curveInfo = WindowTotalDataInstance->getInfomationCurve2DBasicalByID(curveInfoID);
            if (info == nullptr)
                info = _curveInfo;
            dataGraph2DSettings = _curveInfo->getLineChartCenterSettingData();
            if (dataGraph2DSettings == nullptr)
                return;
            tmp = dataGraph2DSettings;
        }
        else
        {
            auto _lineChartWindow = (LineChartWindow*)WindowTotalDataInstance->getGraph2DWindowByID(windowUniversalID);
            dataGraph2DSettings = _lineChartWindow->getLineChartCenterSettingData();
            if (dataGraph2DSettings == nullptr)
                return;
            tmp = dataGraph2DSettings;
        }

      /*  QDomDocument* doc = new QDomDocument();
        QDomElement element = doc->createElement("tmp_root");
        doc->appendChild(element);
        QDomElement lineChartCoordinateSettingDataElement = tmp->m_lineChartCoordinateSettingData->writeToProjectFile(doc, &element);
        QDomElement style2D_DataPropertyElement = tmp->m_style2D_DataProperty->writeToProjectFile(doc, &element, false);

        QString lineChartCoordinateSettingDataElementStr = lineChartCoordinateSettingDataElement.text();
        QString style2D_DataPropertyElementStr = style2D_DataPropertyElement.text();
        QString docStr = doc->toString();

        QString _pyCode = QString("PostProcessing.lineChartChangeLineProperty('%1')")
            .arg(docStr)
            .remove(QRegExp("[\r\n]"));
        emit IBaseSignalInstance->signal_execPYCode(QStringList{_pyCode}, true, false);*/

        //if (dataGraph2DSettings == nullptr)
        //{
        //    return;
        //}
        //
        //LineChartCenterSettingData* tmp = dataGraph2DSettings;   
        //tmp->m_lineChartCoordinateSettingData->copyData(dataGraph2DSettings);

        // x
        QString xTitleText;
        this->SetXTitleAutoFlag(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_isAutoName);
        if (this->GetXTitleAutoFlag())
        {
            slot_autoGetXTitleText(xTitleText);
        }
        else
        {
            xTitleText = tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleText;
        }
        m_customPlot->xAxis->setLabel(xTitleText + m_unit);
        m_customPlot->xAxis->setLabelColor(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleFontColor);
        auto labelFontX = m_customPlot->xAxis->labelFont();
        labelFontX.setPointSize(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleFontSize);
        m_customPlot->xAxis->setLabelFont(labelFontX);
        m_customPlot->xAxis->setSelectedLabelFont(labelFontX);
        auto basePenX = m_customPlot->xAxis->basePen();
        basePenX.setColor(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisColor);
        basePenX.setWidthF(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisThickness);
        m_customPlot->xAxis->setBasePen(basePenX);
        auto selectBasePenX = m_customPlot->xAxis->selectedBasePen();
        selectBasePenX.setWidthF(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisThickness);
        m_customPlot->xAxis->setSelectedBasePen(selectBasePenX);
        m_customPlot->xAxis->setNumberFormat("f");
        m_customPlot->xAxis->setNumberPrecision(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_valuePrecision);
        m_customPlot->xAxis->setTickLabelColor(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisDigitColor);
        auto tickLabelFontX = m_customPlot->xAxis->tickLabelFont();
        tickLabelFontX.setPointSize(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisDigitSize);
        m_customPlot->xAxis->setTickLabelFont(tickLabelFontX);
        auto selectTickLabelFontX = m_customPlot->xAxis->selectedTickLabelFont();
        selectTickLabelFontX.setPointSize(tmp->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_axisDigitSize);
        m_customPlot->xAxis->setSelectedTickLabelFont(selectTickLabelFontX);

        m_unit = '[' + m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit + ']';

        // xRange
        this->SetXAutoFlag(tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoRange);
        if (this->GetXAutoFlag())
        {
            m_customPlot->xAxis->rescale(true);
        }
        else
        {
            auto rangeX = m_customPlot->xAxis->range();
            rangeX.upper = tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_maxValue;
            rangeX.lower = tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_minValue;
            m_customPlot->xAxis->setRange(rangeX);
            m_xAxisRange = rangeX;
        }
        if (tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoStepSize)
        {
            m_customPlot->xAxis->setTicker(QSharedPointer<QCPAxisTicker>(new QCPAxisTicker()));
        }
        else
        {
            QSharedPointer<QCPAxisTickerFixed> fixed(QSharedPointer<QCPAxisTickerFixed>(new QCPAxisTickerFixed()));
            fixed->setTickStep(tmp->m_lineChartCoordinateSettingData->getXAxisRange()->m_customStepSize);
            fixed->setScaleStrategy(QCPAxisTickerFixed::ScaleStrategy::ssNone);
            m_customPlot->xAxis->setTicker(fixed);
        }

        // y
        QString yTitleText;
        this->SetYTitleAutoFlag(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_isAutoName);
        if (!this->GetYTitleAutoFlag())
        {
            yTitleText = tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleText;
        }
        m_customPlot->yAxis->setLabel(yTitleText + m_yUnit);
        m_customPlot->yAxis->setLabelColor(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleFontColor);
        auto labelFontY = m_customPlot->yAxis->labelFont();
        labelFontY.setPointSize(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleFontSize);
        m_customPlot->yAxis->setLabelFont(labelFontY);
        m_customPlot->yAxis->setSelectedLabelFont(labelFontY);
        auto basePenY = m_customPlot->yAxis->basePen();
        basePenY.setColor(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisColor);
        basePenY.setWidthF(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisThickness);
        m_customPlot->yAxis->setBasePen(basePenY);
        auto selectBasePenY = m_customPlot->yAxis->selectedBasePen();
        selectBasePenY.setColor(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisColor);
        selectBasePenY.setWidthF(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisThickness);
        m_customPlot->yAxis->setSelectedBasePen(selectBasePenY);
        m_customPlot->yAxis->setNumberFormat("f");
        m_customPlot->yAxis->setNumberPrecision(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_valuePrecision);
        m_customPlot->yAxis->setTickLabelColor(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisDigitColor);
        auto tickLabelFontY = m_customPlot->yAxis->tickLabelFont();
        tickLabelFontY.setPointSize(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisDigitSize);
        m_customPlot->yAxis->setTickLabelFont(tickLabelFontY);
        auto selectTickLabelFontY = m_customPlot->yAxis->selectedTickLabelFont();
        selectTickLabelFontY.setPointSize(tmp->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_axisDigitSize);
        m_customPlot->yAxis->setSelectedTickLabelFont(selectTickLabelFontY);

        // 单位转换
        for (auto curvePair : m_curveMap)
        {
            auto& info = curvePair.second;
            doInfoUnitConversion(info);
        }


        // yRange
        this->SetYAutoFlag(tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoRange);
        if (this->GetYAutoFlag())
        {
            m_customPlot->yAxis->rescale(true);
        }
        else
        {
            auto rangeY = m_customPlot->yAxis->range();
            rangeY.upper = tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_maxValue;
            rangeY.lower = tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_minValue;
            m_customPlot->yAxis->setRange(rangeY);
            m_yAxisRange = rangeY;
        }
        if (tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoStepSize)
        {
            m_customPlot->yAxis->setTicker(QSharedPointer<QCPAxisTicker>(new QCPAxisTicker()));
        }
        else
        {
            QSharedPointer<QCPAxisTickerFixed> fixed(QSharedPointer<QCPAxisTickerFixed>(new QCPAxisTickerFixed()));
            fixed->setTickStep(tmp->m_lineChartCoordinateSettingData->getYAxisRange()->m_customStepSize);
            fixed->setScaleStrategy(QCPAxisTickerFixed::ScaleStrategy::ssNone);
            m_customPlot->yAxis->setTicker(fixed);
        }

        // grid
        m_customPlot->xAxis->grid()->setVisible(tmp->m_lineChartCoordinateSettingData->getGrid()->m_isMainGridLineDisplay);
        m_customPlot->yAxis->grid()->setVisible(tmp->m_lineChartCoordinateSettingData->getGrid()->m_isMainGridLineDisplay);
        auto penGrid = m_customPlot->xAxis->grid()->pen();
        penGrid.setColor(tmp->m_lineChartCoordinateSettingData->getGrid()->m_mainGridLineColor);
        penGrid.setStyle(Qt::PenStyle(tmp->m_lineChartCoordinateSettingData->getGrid()->m_mainGridLineStyle + 1));
        penGrid.setWidthF(tmp->m_lineChartCoordinateSettingData->getGrid()->m_mainGridLineThickness);
        m_customPlot->xAxis->grid()->setPen(penGrid);
        m_customPlot->yAxis->grid()->setPen(penGrid);
        m_customPlot->xAxis->grid()->setSubGridVisible(tmp->m_lineChartCoordinateSettingData->getGrid()->m_isSecondaryGridLineDisplay);
        m_customPlot->yAxis->grid()->setSubGridVisible(tmp->m_lineChartCoordinateSettingData->getGrid()->m_isSecondaryGridLineDisplay);
        auto subGridPen = m_customPlot->xAxis->grid()->subGridPen();
        subGridPen.setColor(tmp->m_lineChartCoordinateSettingData->getGrid()->m_secondaryGridLineColor);
        subGridPen.setStyle(Qt::PenStyle(tmp->m_lineChartCoordinateSettingData->getGrid()->m_secondaryGridLineStyle + 1));
        subGridPen.setWidthF(tmp->m_lineChartCoordinateSettingData->getGrid()->m_secondaryGridLineThickness);
        m_customPlot->xAxis->grid()->setSubGridPen(subGridPen);
        m_customPlot->yAxis->grid()->setSubGridPen(subGridPen);

        // title
        auto title = qobject_cast<QCPTextElement*>(m_customPlot->plotLayout()->element(0, 0));
        if (title != nullptr)
        {
            title->setText(tmp->m_lineChartCoordinateSettingData->getTitle()->m_titleName);
            title->setTextColor(tmp->m_lineChartCoordinateSettingData->getTitle()->m_titleFontColor);
            auto fontTitle = title->font();
            fontTitle.setPointSize(tmp->m_lineChartCoordinateSettingData->getTitle()->m_titleFontSize);
            title->setFont(fontTitle);
            title->setSelectedFont(fontTitle);
        }

        // legend
        m_customPlot->legend->setTextColor(tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendFontColor);
        auto fontLegend = m_customPlot->legend->font();
        fontLegend.setPointSize(tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendFontSize);
        m_customPlot->legend->setFont(fontLegend);
        m_customPlot->legend->setSelectedFont(fontLegend);
        auto borderPen = m_customPlot->legend->borderPen();
        borderPen.setColor(tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendLineColor);
        borderPen.setWidthF(tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendLineThickness);
        m_customPlot->legend->setBorderPen(borderPen);
        auto selectBorderPen = m_customPlot->legend->selectedBorderPen();
        selectBorderPen.setWidthF(tmp->m_lineChartCoordinateSettingData->getLegend()->m_legendLineThickness);
        m_customPlot->legend->setSelectedBorderPen(selectBorderPen);

        QCPGraph* plottable = nullptr;
        if (info != nullptr)
            plottable = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        else
        {
            plottable = dynamic_cast<QCPGraph*>(m_doubleClickPlottable);
            if (nullptr == m_doubleClickPlottable)
            {
                if (dataGraph2DSettings->m_lineChartCoordinateSettingData->indexOfGraph >= 0 && dataGraph2DSettings->m_lineChartCoordinateSettingData->indexOfGraph < m_graphs.size())
                {
                    plottable = dynamic_cast<QCPGraph*>(m_graphs.at(dataGraph2DSettings->m_lineChartCoordinateSettingData->indexOfGraph));
                }
            }
        }
        if (plottable != nullptr)
        {
            // data
            for (auto curvePair : m_curveMap)
            {
                auto& info = curvePair.second;
                if (info->getCurveLineAddress() == plottable)
                {
                    if (tmp->m_style2D_DataProperty->m_resultDataName != plottable->name() && bCheckName)
                    {
                        curvePair.first->setData(true);
                        curvePair.first->setText(tmp->m_style2D_DataProperty->m_resultDataName);
                        slot_renameCheck();
                        // plottable->setName(tmp->m_lineChartCoordinateSettingData->getDataProperty()->m_resultDataName);
                        // info->setCurveName(tmp->m_lineChartCoordinateSettingData->getDataProperty()->m_resultDataName);
                    }
                    break;
                }
            }
            auto penPlottable = plottable->pen();
            penPlottable.setColor(tmp->m_style2D_DataProperty->m_dataLineColor);
            penPlottable.setStyle(Qt::PenStyle(tmp->m_style2D_DataProperty->m_dataLineStyle + 1));
            penPlottable.setWidthF(tmp->m_style2D_DataProperty->m_dataLineThickness);
            plottable->setPen(penPlottable);
            auto selectPenPlottable = plottable->selectionDecorator()->pen();
            selectPenPlottable.setStyle(Qt::PenStyle(tmp->m_style2D_DataProperty->m_dataLineStyle + 1));
            selectPenPlottable.setWidthF(tmp->m_style2D_DataProperty->m_dataLineThickness > 2 ? tmp->m_style2D_DataProperty->m_dataLineThickness : 2);
            plottable->selectionDecorator()->setPen(selectPenPlottable);
            auto scatterStyle = plottable->scatterStyle();
            if (tmp->m_style2D_DataProperty->m_isDisplaySymbol)
            {
                scatterStyle.setShape(QCPScatterStyle::ScatterShape(tmp->m_style2D_DataProperty->m_symbolStyle + 1));
            }
            else
            {
                scatterStyle.setShape(QCPScatterStyle::ssNone);
            }
            scatterStyle.setSize(tmp->m_style2D_DataProperty->m_symbolSize * 2);
            scatterStyle.setPen(QPen(tmp->m_style2D_DataProperty->m_symbolColor));
            plottable->setScatterStyle(scatterStyle);
        }

        m_customPlot->replot();

        updateAxisRange();
        adjustLegendColumns();

        QCoreApplication::processEvents(); // 让 UI 有机会更新,防止获取高度axisRect()->rect().height()失败
        QTimer::singleShot(0, this, [=]() {
            adjustLegendColumns();
            });
        m_customPlot->rescaleAxes(true);
        m_customPlot->replot();
    }

    void LineChartWindow::slot_showHideItemActor(QStandardItem* item)
    {
        if (item == nullptr)
            return;

        const auto& info = getCurveInfoByItem(item);
        auto plottable = info->getCurveLineAddress();
        if (plottable == nullptr)
            return;
        plottable->setVisible(item->checkState());
        auto tracerPropertyWidget = m_tracerPropertyWidget;
        // 隐藏该曲线上的标记
        for (int i = 0; i < tracerPropertyWidget->rowCount(); ++i)
        {
            auto tracer = tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
            if (tracer->getCurveInfoID() == info->getInformationID())
                //if (tracer->graph() == plottable)
            {
                tracer->setVisible(item->checkState());
            }
        }
        auto measureTableWidget = m_measureTableWidget;
        for (int i = 0; i < measureTableWidget->rowCount(); ++i)
        {
            auto tracer = measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
            if (tracer->getCurveInfoID() == info->getInformationID())
            {
                tracer->setVisible(item->checkState()&& tracer->GetName()!="平均值");
            }
        }
        m_customPlot->replot();
    }

    void LineChartWindow::initConnections()
    {
        connect(m_settings, &LineChartSidebarSettingsDialog::signal_generateANewGraphCurve,
            this, &LineChartWindow::slot_generateANewGraphCurve);

        connect(m_settings, &LineChartSidebarSettingsDialog::signal_chosenItemsChanged,
            this, &LineChartWindow::slot_chosenItemsChanged);
        connect(m_settings, &LineChartSidebarSettingsDialog::signal_updateCurveData,
            this, &LineChartWindow::slot_updateCurveData);
        connect(m_settings, &LineChartSidebarSettingsDialog::signal_updateCurveData,
            this, &LineChartWindow::slot_updateName);

        connect(m_settings, &LineChartSidebarSettingsDialog::signal_legendTitleFontFamilyChanged,
            this, &LineChartWindow::slot_legendTitleFontFamilyChanged);
        connect(m_settings, &LineChartSidebarSettingsDialog::signal_legendTitleFontSizeChanged,
            this, &LineChartWindow::slot_legendTitleFontSizeChanged);

        connect(m_settings, &LineChartSidebarSettingsDialog::signal_renameGraph,
            this, &LineChartWindow::slot_renameGraph);
        connect(m_settings, &LineChartSidebarSettingsDialog::signal_renameCheck,
            this, &LineChartWindow::slot_renameCheck);

        connect(m_customPlot, &QCustomPlot::plottableDoubleClick, [this](QCPAbstractPlottable* plottable, int dataIndex, QMouseEvent* event)
            {
                m_doubleClickPlottable = plottable;
                if (m_customPlot->xAxis != nullptr)
                {
                    QCPGraph* graph = dynamic_cast<QCPGraph*>(plottable);
                    if (graph != nullptr)
                    {
                        slot_LinePropertyShow(graph, 7);
                    }
                } });

                connect(m_customPlot, &QCustomPlot::itemDoubleClick, [this](QCPAbstractItem* item, QMouseEvent* event)
                    {
                        auto tracerPropertyWidget = m_tracerPropertyWidget;
                        for (int i = 0; i < tracerPropertyWidget->rowCount(); ++i)
                        {
                            auto tracer = tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value< LineChartTracer* >();
                            if (tracer == item || tracer->GetLabel() == item || tracer->GetArrow() == item)
                            {
                                slot_TracerPropertyShow(tracer);
                                return;
                            }
                        }
                        for (auto guideLine : m_customPlot->GetLineArray())
                        {
                            if (guideLine == item || guideLine->GetLabel() == item || guideLine->GetArrow() == item)
                            {
                                emit IWidgetSignalInstance->signal_exitAddMarkerState();
                                slot_GuideLinePropertyShow(guideLine);
                                return;
                            }
                        } });

                        connect(m_customPlot, &QCustomPlot::axisDoubleClick, [this](QCPAxis* axis, QCPAxis::SelectablePart part, QMouseEvent* event)
                            {
                                if (axis == m_customPlot->xAxis)
                                {
                                    slot_LinePropertyShow(nullptr, 0);
                                }
                                else if (axis == m_customPlot->yAxis)
                                {
                                    slot_LinePropertyShow(nullptr, 2);
                                } });

                                auto title = qobject_cast<QCPTextElement*>(m_customPlot->plotLayout()->element(0, 0));
                                if (title != nullptr)
                                {
                                    connect(title, &QCPTextElement::doubleClicked, [this](QMouseEvent* event)
                                        { slot_LinePropertyShow(nullptr, 5); });
                                }

                                connect(m_customPlot, &QCustomPlot::legendDoubleClick, [this](QCPLegend* legend, QCPAbstractLegendItem* item, QMouseEvent* event)
                                    {
                                        auto plottableLegendItem = qobject_cast<QCPPlottableLegendItem*>(item);
                                        if (plottableLegendItem == nullptr) {
                                            slot_LinePropertyShow(nullptr, 6);
                                        }
                                        else {
                                            auto graph = qobject_cast<QCPGraph*>(plottableLegendItem->plottable());
                                            if (graph != nullptr)
                                            {
                                                m_doubleClickPlottable = graph;
                                                slot_LinePropertyShow(graph, 7);
                                            }
                                        } });

                                        auto listView = m_settings->getCurveNameListView();
                                        if (listView != nullptr)
                                        {
                                            connect(listView, &QListView::doubleClicked, [this](const QModelIndex& index)
                                                {
                                                    auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
                                                    auto item = model->itemFromIndex(index);
                                                    QCPGraph* graph = qobject_cast<QCPGraph*>(getCurveInfoByItem(item)->getCurveLineAddress());
                                                    if (m_customPlot->xAxis != nullptr)
                                                    {
                                                        if (graph != nullptr)
                                                        {
                                                            m_doubleClickPlottable = graph;
                                                            slot_LinePropertyShow(graph, 7);
                                                        }
                                                    } });
                                        }

                                        connect(m_tracerPropertyWidget, &TracerTableWidget::signal_doubleClicked, this, &LineChartWindow::slot_TracerPropertyShow);

                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_showHideItemActor,
                                            this, &LineChartWindow::slot_showHideItemActor);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_changeAllCurveVariableAxis,
                                            this, &LineChartWindow::slot_changeAllCurveVariableAxis);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_editSelectedGraph, this, &LineChartWindow::slot_editSelectedGraph);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_removeSelectedGraph, this, &LineChartWindow::slot_removeSelectedGraph);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_copySelectedGraph, this, &LineChartWindow::slot_copySelectedGraph);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_deleteAllCurve, this, &LineChartWindow::slot_removeAlldGraph);

                                        connect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);
                                        connect(m_customPlot, &Curve2DPlotor::signal_removeSelectedGraph, this, &LineChartWindow::slot_removeSelectedGraph);
                                        connect(m_customPlot, &Curve2DPlotor::signal_removeAlldGraph, this, &LineChartWindow::slot_removeAlldGraph);

                                        connect(m_customPlot, &Curve2DPlotor::signal_addTracer, this, &LineChartWindow::slot_AddTracer);
                                        connect(m_customPlot, &Curve2DPlotor::mouseMove, this, &LineChartWindow::slot_ShowPreviewTracer);
                                        connect(m_customPlot, &Curve2DPlotor::signal_removeSelectedTracer, this, &LineChartWindow::slot_removeSelectedTracer);
                                        connect(m_customPlot, &Curve2DPlotor::signal_removeAlldTracer, this, &LineChartWindow::slot_removeAllTracer);
                                        connect(m_customPlot, &QCustomPlot::beforeReplot, this, &LineChartWindow::slot_updateBeamBandwidthProperty);
                                        connect(m_customPlot, &QCustomPlot::beforeReplot, this, &LineChartWindow::slot_updateStandingWaveBandwidthProperty);

                                        connect(m_customPlot, &QCustomPlot::afterReplot, m_tracerPropertyWidget, &TracerTableWidget::slot_updateTracerProperty);
                                        connect(m_customPlot, &QCustomPlot::selectionChangedByUser, m_tracerPropertyWidget, &TracerTableWidget::slot_updateTracerChange);
                                        connect(m_customPlot, &QCustomPlot::selectionChangedByUser, m_measureTableWidget, &MeasureTableWidget::slot_updateTracerChange);
                                        connect(m_customPlot, &QCustomPlot::beforeReplot, m_measureTableWidget, &MeasureTableWidget::slot_updateTracerProperty);

                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_getCurveNames, this, &LineChartWindow::slot_getCurveNames);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_getSidebarCurveDataSource, this, &LineChartWindow::slot_getSidebarCurveDataSource);
                                        connect(m_settings, &LineChartSidebarSettingsDialog::signal_calculationCheck, this, &LineChartWindow::slot_calculationCheck);

                                        connect(m_customPlot, &QCustomPlot::beforeReplot, this, &LineChartWindow::slot_updateUnit);
                                        connect(m_customPlot, &QCustomPlot::beforeReplot, this, &LineChartWindow::slot_checkStandardCcurveState);
                                        connect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraphState);

                                        connect(m_customPlot, &Curve2DPlotor::signal_renameGraph, this, &LineChartWindow::slot_renameGraph);
                                        connect(m_customPlot, &Curve2DPlotor::signal_copyGraph, this, &LineChartWindow::slot_copyGraph);
                                        connect(m_customPlot, &Curve2DPlotor::signal_pasteGraph, this, &LineChartWindow::signal_infoListPaste);
                                        connect(m_customPlot, &Curve2DPlotor::signal_showLocalScope, [this](bool isEdit)
                                            {
                                                auto _DialogAddLocalRange = new DialogAddLocalRange();
                                                QStringList graphNames;
                                                for (int i = 0; i < m_customPlot->graphCount(); ++i)
                                                {
                                                    graphNames.append(m_customPlot->graph(i)->name());
                                                }
                                                _DialogAddLocalRange->setCurveNameList(graphNames);
                                                _DialogAddLocalRange->setIsEdit(isEdit);
                                                for (auto& curvePair : m_curveMap)
                                                {
                                                    auto& info = curvePair.second;
                                                    QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
                                                    if (graph->selected() && info->getIsNewData())
                                                    {
                                                        auto params = curvePair.first->data(Qt::UserRole + 3).toString().split(",", QString::SkipEmptyParts);
                                                        _DialogAddLocalRange->setInit(params);
                                                    }
                                                }
                                                connect(_DialogAddLocalRange, &DialogAddLocalRange::signal_sendLocalScopeData, this, &LineChartWindow::slot_localScope);
                                                _DialogAddLocalRange->showWindow(); });

                                        connect(IWidgetSignalInstance, &BaseWidget::IWidgetSignal::signal_closeTree, this, &LineChartWindow::slot_closeTree);
    }

    void LineChartWindow::slot_updateSelectedGraph()
    {
        disconnect(m_settings, &LineChartSidebarSettingsDialog::signal_chosenItemsChanged,
            this, &LineChartWindow::slot_chosenItemsChanged);
        QList<Info2DPointer> curInfoList;

        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        for (auto curvePair : m_curveMap)
        {
            auto info = curvePair.second;
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graph->selected())
            {
                QModelIndex index = model->indexFromItem(curvePair.first);
                selectionModel->select(index, QItemSelectionModel::Select);
                curInfoList.append(info);
            }
            else
            {
                QModelIndex index = model->indexFromItem(curvePair.first);
                selectionModel->select(index, QItemSelectionModel::Deselect);
            }
        }

        // 设置框中选中的曲线发生改变->根据曲线信息更新m_settings
        if (curInfoList.isEmpty())
        {
            // 折叠控制面板
            m_settings->hideCurvePropertylPanel();
        }
        else
        {
            // 各个曲线信息的交集
            Info2DPointer commonInfo = Info2DPointer::create();
            auto isSuc = InfomationCurve2DBasical::getCommonData(curInfoList, commonInfo);
            if (!isSuc)
            {
                // TODO 警告
                return;
            }
            m_settings->setCurvePropertyPanelState(commonInfo);
        }
        connect(m_settings, &LineChartSidebarSettingsDialog::signal_chosenItemsChanged,
            this, &LineChartWindow::slot_chosenItemsChanged);
    }

    void LineChartWindow::slot_editSelectedGraph()
    {
        QString params;
        for (auto& curvePair : m_curveMap)
        {
            QCPGraph* graph = qobject_cast<QCPGraph*>(curvePair.second->getCurveLineAddress());
            if (graph->selected())
            {
                params = curvePair.first->data(Qt::UserRole + 3).toString();
                break;
            }
        }

        if (params.isEmpty())
        {
            return;
        }

        disconnect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);

        auto SEParamList = params.split(",", QString::SkipEmptyParts);
        DataAnalysisType type = (DataAnalysisType)SEParamList.front().toInt();
        if (type == pst::LineChartWindow::HIRF)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonHirfExtrapolationClicked();
        }
        else if (type == pst::LineChartWindow::Effectiveness)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonShieldingEfficiencyClicked();
        }
        else if (type == pst::LineChartWindow::Lighting)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonThunderstormZoneClicked();
        }
        else if (type == pst::LineChartWindow::TransferFunction)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonTransferFunctionClicked();
        }
        else if (type == pst::LineChartWindow::IPL)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonIPLCalculationClicked();
        }
        else if (type == pst::LineChartWindow::WaveformAnalysis)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonWaveformAnalysisClicked();
        }
        else if (type == pst::LineChartWindow::SmoothData)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonCurveSmoothingClicked();
        }
        else if (type == pst::LineChartWindow::Interpolation)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonLinearInterpolationClicked();
        }
        else if (type == pst::LineChartWindow::InterpolationSingleAxisX)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonLogarithmicInterpolationSingleAxisXClicked();
        }
        else if (type == pst::LineChartWindow::InterpolationSingleAxisY)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonLogarithmicInterpolationSingleAxisYClicked();
        }
        else if (type == pst::LineChartWindow::InterpolationDoubleAxis)
        {
            MainWindowSignalHandlerInstance->slot_toolButtonLogarithmicInterpolationDoubleAxisClicked();
        }
        else if (type == pst::LineChartWindow::LocalRange)
        {
            m_customPlot->signal_showLocalScope(true);
        }

        connect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);
    }

    void LineChartWindow::slot_removeSelectedGraph()
    {
        disconnect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);

        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        QList<QStandardItem*> removeList;
        QList<LineChartTracer*> tracerList;

        QSet<QPair<QStandardItem*, Info2DPointer>> toDelete; //选中的
        QSet<QPair<QStandardItem*, Info2DPointer>> toDeleteWithHirfPair; //选中的 + hirf对
        for (auto curvePair : m_curveMap)
        {
            auto info = curvePair.second;
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graph->selected())
            {
                toDelete.insert(curvePair);
            }
        }

        for (auto curvePair : m_curveMap) //找出hirf对
        {
            auto data1 = curvePair.first->data(Qt::UserRole + 3).toString();
            if (data1.isEmpty())
            {
                continue;
            }
            auto params = data1.split(",", QString::SkipEmptyParts);
            if (params[0].toInt() != pst::LineChartWindow::HIRF)
            {
                continue;
            }
            for (auto interPair : toDelete)
            {
                auto data2 = interPair.first->data(Qt::UserRole + 3).toString();
                if (data1 == data2)
                {
                    toDeleteWithHirfPair.insert(curvePair);
                }
            }
        }
        for (auto i : toDelete)
        {
            toDeleteWithHirfPair.insert(i);
        }

        for (auto curvePair : toDeleteWithHirfPair)
        {
            auto info = curvePair.second;
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            //if (graph->selected())
            //{
            QModelIndex index = model->indexFromItem(curvePair.first);
            QSignalBlocker blocker(m_settings->getCurveNameListView()->model());
            model->removeRow(index.row());
            auto tracerPropertyWidget = m_tracerPropertyWidget;
            // 获取该曲线上的标记点，后续删除
            for (int i = 0; i < tracerPropertyWidget->rowCount(); ++i)
            {
                auto tracer = tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (tracer->graph() == graph)
                {
                    tracerList.append(tracer);
                }
            }
            auto measureTableWidget = m_measureTableWidget;
            // 获取该曲线上的测量点，后续删除
            for (int i = 0; i < measureTableWidget->rowCount(); ++i)
            {
                auto tracer = measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (tracer->GetLayerable() == graph)
                {
                    tracerList.append(tracer);
                }
            }
            info->setCurveLineAddress(nullptr);
            m_customPlot->removeGraph(graph);
            removeList.append(curvePair.first);
            //}
        }
        slot_removeSelectedTracer(tracerList);

        for (auto i : removeList)
        {
            auto _infoID = getCurveInfoByItem(i)->getInformationID();
            WindowTotalDataInstance->removeInfomationCurve2DBasicalByID(_infoID);
            removeCurveItemInfoPair(i);
        }
        m_customPlot->replot();
        emit IWidgetSignalInstance->signal_exitAddMarkerState();

        connect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);
    }

    void LineChartWindow::slot_removeGraphs(const QList<QCPGraph*>& graphList)
    {
        disconnect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);

        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        QList<QStandardItem*> removeList;
        QList<LineChartTracer*> tracerList;
        for (auto curvePair : m_curveMap)
        {
            auto info = curvePair.second;
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graphList.contains(graph))
            {
                QModelIndex index = model->indexFromItem(curvePair.first);
                model->removeRow(index.row());
                auto tracerPropertyWidget = m_tracerPropertyWidget;
                // 获取该曲线上的标记点，后续删除
                for (int i = 0; i < tracerPropertyWidget->rowCount(); ++i)
                {
                    auto tracer = tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                    if (tracer->graph() == graph)
                    {
                        tracerList.append(tracer);
                    }
                }
                auto measureTableWidget = m_measureTableWidget;
                // 获取该曲线上的测量点，后续删除
                for (int i = 0; i < measureTableWidget->rowCount(); ++i)
                {
                    auto tracer = measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                    if (tracer->GetLayerable() == graph)
                    {
                        tracerList.append(tracer);
                    }
                }
                m_customPlot->removeGraph(graph);
                removeList.append(curvePair.first);
            }
        }
        slot_removeSelectedTracer(tracerList);

        for (auto i : removeList)
        {
            auto _infoID = getCurveInfoByItem(i)->getInformationID();
            WindowTotalDataInstance->removeInfomationCurve2DBasicalByID(_infoID);
            removeCurveItemInfoPair(i);
        }
        m_customPlot->replot();
        emit IWidgetSignalInstance->signal_exitAddMarkerState();

        connect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);
    }

    void LineChartWindow::slot_removeGraphs(const QList<QString>& graphNameList)
    {
        disconnect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);

        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        QList<QStandardItem*> removeList;
        QList<LineChartTracer*> tracerList;
        for (auto curvePair : m_curveMap)
        {
            auto info = curvePair.second;
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graphNameList.contains(graph->name()))
            {
                QModelIndex index = model->indexFromItem(curvePair.first);
                model->removeRow(index.row());
                auto tracerPropertyWidget = m_tracerPropertyWidget;
                // 获取该曲线上的标记点，后续删除
                for (int i = 0; i < tracerPropertyWidget->rowCount(); ++i)
                {
                    auto tracer = tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                    if (tracer->graph() == graph)
                    {
                        tracerList.append(tracer);
                    }
                }
                auto measureTableWidget = m_measureTableWidget;
                // 获取该曲线上的测量点，后续删除
                for (int i = 0; i < measureTableWidget->rowCount(); ++i)
                {
                    auto tracer = measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                    if (tracer->GetLayerable() == graph)
                    {
                        tracerList.append(tracer);
                    }
                }
                m_customPlot->removeGraph(graph);
                removeList.append(curvePair.first);
            }
        }
        slot_removeSelectedTracer(tracerList);

        for (auto i : removeList)
        {
            auto _infoID = getCurveInfoByItem(i)->getInformationID();
            WindowTotalDataInstance->removeInfomationCurve2DBasicalByID(_infoID);
            removeCurveItemInfoPair(i);
        }
        m_customPlot->replot();
        emit IWidgetSignalInstance->signal_exitAddMarkerState();

        connect(m_customPlot, &Curve2DPlotor::signal_updateSelectedGraph, this, &LineChartWindow::slot_updateSelectedGraph);
    }

    void LineChartWindow::slot_copySelectedGraph()
    {
        auto func = [](QStandardItem* item, const Info2DPointer& info) -> QString
            {
                QString name;
                if (item == nullptr || info->getCurveLineAddress() == nullptr)
                {
                    return name;
                }
                name = info->getCurveName();
                if (!item->data().isNull() && item->data().toBool())
                {
                    return name;
                }
                name.remove(QRegularExpression("\\[.*?]$"));
                return name;
            };
        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();

        QSet<QString> allCurveNames;
        QList<QPair<QStandardItem*, Info2DPointer>> m_curveMaps;
        for (auto curvePair : m_curveMap)
        {
            QString curveName = func(curvePair.first, curvePair.second);
            allCurveNames.insert(curveName);
            m_curveMaps.append(curvePair);
        }
        for (auto curvePair : m_curveMaps)
        {
            auto info = Info2DPointer::create(*curvePair.second);
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graph->selected())
            {
                QString curveName = func(curvePair.first, curvePair.second);
                QString finalName = autoIncrementName(curveName);
                //QString finalName = GlobalHelperInstance->autoIncreaseName(allCurveNames, curveName);
                info->setCurveName(finalName);
                bool isAutoName = false;
                if (!curvePair.first->data().isNull() && curvePair.first->data().toBool())
                {
                    isAutoName = true;
                }
                m_execSuccessFlag = true;
                addNewGraph(info, "", isAutoName);
                if (!m_execSuccessFlag)
                {
                    return;
                }
                m_addCurveInfo.append(info);
            }
        }
        emit IWidgetSignalInstance->signal_exitAddMarkerState();
        slot_updateName();
    }

    QString LineChartWindow::autoIncrementName(QString name)
    {
        QString pattern = QString("^%1_([0-9]+)$") .arg(QRegularExpression::escape(name));
        QRegularExpression reg(pattern);

        QListView* listView = m_settings->getCurveNameListView();
        QAbstractItemModel* model = listView->model();

        if (model)
        {
            int maxNumber = 0;
            for (int row = 0; row < model->rowCount(); ++row)
            {
                QModelIndex index = model->index(row, 0); // 第0列
                QString text = model->data(index, Qt::DisplayRole).toString();
                QString str = text.remove(QRegularExpression("\\[.*?]$"));
                QRegularExpressionMatch match = reg.match(str);
                if (match.hasMatch())
                {
                    QString numberStr = match.captured(1);
                    int number = numberStr.toInt();
                    maxNumber = std::max(maxNumber, number);
                }

            }
            maxNumber++;
            return QString("%1_%2")
                .arg(name)
                .arg(QString::number(maxNumber));
        }
        else
        {
            return name;
        }

    }

    void LineChartWindow::slot_removeAlldGraph()
    {
        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());

        model->clear();
        QList<LineChartTracer*> tracerList;
        for (int i = 0; i < m_customPlot->graphCount(); ++i)
        {
            auto tracerPropertyWidget = m_tracerPropertyWidget;
            // 获取该曲线上的标记点，后续删除
            for (int j = 0; j < tracerPropertyWidget->rowCount(); ++j)
            {
                auto tracer = tracerPropertyWidget->item(j, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (tracer->graph() == m_customPlot->graph(i))
                {
                    tracerList.append(tracer);
                }
            }
            auto measureTableWidget = m_measureTableWidget;
            // 获取该曲线上的测量点，后续删除
            for (int j = 0; j < measureTableWidget->rowCount(); ++j)
            {
                auto tracer = measureTableWidget->item(j, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (tracer->GetLayerable() == m_customPlot->graph(i))
                {
                    tracerList.append(tracer);
                }
            }
        }
        slot_removeAllTracer(tracerList);
        m_customPlot->clearGraphs();
        m_customPlot->replot();
        m_settings->hideCurvePropertylPanel();
        emit signal_updateMeasureButtonState(0);

        for (auto infoPair : m_curveMap)
        {
            auto _infoID = infoPair.second->getInformationID();
            WindowTotalDataInstance->removeInfomationCurve2DBasicalByID(_infoID);
        }
        m_curveMap.clear();
        m_graphs.clear();
    }

    void LineChartWindow::slot_renameGraph()
    {
        auto listView = m_settings->getCurveNameListView();
        QModelIndexList selectedIndexes = listView->selectionModel()->selectedIndexes();
        if (selectedIndexes.size() != 1)
        {
            return;
        }
        emit IWidgetSignalInstance->signal_exitAddMarkerState();
        listView->setCurrentIndex(selectedIndexes.first());
        listView->edit(selectedIndexes.first());
    }

    void LineChartWindow::slot_copyGraph()
    {
        QList<Info2DPointer> infoListCopy;

        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        for (auto curvePair : m_curveMap)
        {
            Info2DPointer info = Info2DPointer::create(*curvePair.second);
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graph->selected())
            {
                infoListCopy.append(info);
            }
        }
        if (!infoListCopy.isEmpty())
        {
            emit signal_infoListCopy(&infoListCopy);
        }
        emit IWidgetSignalInstance->signal_exitAddMarkerState();
    }

    void LineChartWindow::slot_renameCheck()
    {
        auto listView = m_settings->getCurveNameListView();
        QModelIndexList selectedIndexes = listView->selectionModel()->selectedIndexes();
        if (selectedIndexes.size() != 1)
        {
            return;
        }
        auto model = (QStandardItemModel*)listView->model();
        auto item = model->itemFromIndex(selectedIndexes.first());
        auto& info = getCurveInfoByItem(item);
        auto graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        if (item->text().isEmpty())
        {
            item->setText(graph->name());
            IdaDialogMsg::showDialog(this, QString("命名不能为空，请重新编辑。"), EDialogMsg::Error, tr("重命名错误"));
            return ;
        }
        for (auto curvePair : m_curveMap)
        {
            auto tmpItem = curvePair.first;
            if (tmpItem == item)
            {
                continue;
            }
            if (item->text() == tmpItem->text())
            {
                EDialogMsgResult _result = IdaDialogMsg::showDialog(this, QString("当前名称已存在，请重新编辑。"), EDialogMsg::Error, tr("重命名错误"));
                item->setText(graph->name());
                return;
            }
        }
        if (item->text() != graph->name())
        {
            item->setData(true);
            info->setCurveName(item->text());
            graph->setName(item->text());
            item->setToolTip(item->text());
            Style2D_DataProperty* property = info->getCurvePropertyData();
            property->m_resultDataName = item->text();

            
            QString _pyCode = QString("PostProcessing.lineChartSidebarSettingsRenameCheck('%1')")
                                  .arg(item->text())
                                  .remove(QRegExp("[\r\n]"));
            emit IBaseSignalInstance->signal_execPYCode(QStringList{_pyCode}, true, false);


        }
        m_customPlot->replot();
    }

    void LineChartWindow::slot_AddTracer()
    {
        auto isShowPreviewTracer = m_customPlot->GetIsShowPreviewTracer();
        if (!isShowPreviewTracer)
        {
            return;
        }
        auto previewTracer = m_customPlot->GetPreviewTracer();
        if (previewTracer == nullptr || !previewTracer->visible())
        {
            return;
        }

        auto _graph = previewTracer->graph();

        QString name = "Marker" + QString::number(++m_tracerIndex);
        auto existNames = getMarkerNameMap().values();
        for (int i = 0; i < INT_MAX; ++i)
        {
            if (!existNames.contains(name))
            {
                break;
            }
            name = "Marker" + QString::number(++m_tracerIndex);
        }

        int infoId = -1;
        for (auto _curveInfoPair : m_curveMap)
        {
            if (_curveInfoPair.second->getCurveLineAddress() == _graph)
            {
                //tracer->setCurveInfoID(_curveInfoPair.second->getInformationID());
                infoId = _curveInfoPair.second->getInformationID();
            }
        }

        QString trackerData = serializeTracer(previewTracer, 
            m_customPlot, name, infoId, m_tracerIndex);
   
        QString _pyCode = QString("PostProcessing.lineChartWindowAddTracer(%1,'%2')")
            .arg(m_windowUniversalID)
            .arg(trackerData);
        emit IBaseSignalInstance->signal_execPYCode(QStringList{ _pyCode }, true, false);

        pyAddTracer(trackerData);
    }

    void LineChartWindow::slot_ShowPreviewTracer(QMouseEvent* event)
    {
        if (!m_customPlot->GetIsShowPreviewTracer())
        {
            return;
        }
        auto previewTracer = m_customPlot->GetPreviewTracer();
        if (previewTracer == nullptr)
        {
            return;
        }
        double distTmp = std::numeric_limits<double>::max();
        QCPGraph* graphTmp = nullptr;
        for (int i = 0; i < m_customPlot->graphCount(); ++i)
        {
            QCPGraph* g = qobject_cast<QCPGraph*>(m_customPlot->graph(i));
            double dist = g->selectTest(event->pos(), false);
            // 多条曲线接近时，比较最近的曲线显示预览标记
            if (dist >= 0 && dist < m_customPlot->selectionTolerance() && dist < distTmp)
            {
                distTmp = dist;
                graphTmp = g;
            }
        }
        if (graphTmp != nullptr)
        {
            previewTracer->setVisible(true);
            previewTracer->setGraph(graphTmp);
            previewTracer->setGraphKey(this->m_customPlot->xAxis->pixelToCoord(event->pos().x()));
            previewTracer->updatePosition();
        }
        else
        {
            previewTracer->setVisible(false);
        }
        m_customPlot->replot();
    }

    void LineChartWindow::slot_removeSelectedTracer(const QList<LineChartTracer*>& selectTracers)
    {
        for (auto tracer : selectTracers)
        {
            auto tracerPropertyWidget = m_tracerPropertyWidget;
            for (int i = 0; i < tracerPropertyWidget->rowCount(); ++i)
            {
                auto t = tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (t == tracer)
                {
                    tracerPropertyWidget->removeRow(i);
                    break;
                }
            }
            if (tracerPropertyWidget->rowCount() == 0)
            {
                tracerPropertyWidget->hide();
            }
            auto measureTableWidget = m_measureTableWidget;
            for (int i = 0; i < measureTableWidget->rowCount(); ++i)
            {
                auto t = measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (t == tracer)
                {
                    measureTableWidget->removeRow(i);
                    break;
                }
            }
            if (measureTableWidget->rowCount() == 0)
            {
                measureTableWidget->hide();
            }
            m_customPlot->removeItem(tracer);
        }
        m_customPlot->replot();
    }

    void LineChartWindow::slot_removeAllTracer(const QList<LineChartTracer*>& tracers)
    {
        auto tracerPropertyWidget = m_tracerPropertyWidget;
        tracerPropertyWidget->clearContents();
        tracerPropertyWidget->setRowCount(0);
        tracerPropertyWidget->hide();
        auto measureTableWidget = m_measureTableWidget;
        measureTableWidget->clearContents();
        measureTableWidget->setRowCount(0);
        measureTableWidget->hide();
        for (auto tracer : tracers)
        {
            m_customPlot->removeItem(tracer);
        }
        m_customPlot->replot();
    }

    void LineChartWindow::slot_TracerPropertyShow(LineChartTracer* tracer)
    {
        if (tracer == nullptr)
        {
            return;
        }
        emit IWidgetSignalInstance->signal_exitAddMarkerState();
        auto tmp = tracer->getStyle2DTracerProperty();
        
        //m_doubleClickTracer = tracer;
        auto _dialog = new DialogTracer2DSettings(this);
        _dialog->setTracerID(tracer->getTracerIndex());
        connect(_dialog, &DialogTracer2DSettings::signal_sendData, this, &LineChartWindow::slot_ChangeTracerProperty);
        
        for (int i = 0; i < m_tracerPropertyWidget->rowCount(); ++i)
        {
            auto t = m_tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
            if (t->GetName() == tracer->GetName())
            {
                _dialog->setTracerPropertyWidgetRowIndex(i);
                break;
            }
        }

        QHash<int, QString> map = getMarkerNameMap();
        for (auto it = map.cbegin(); it != map.cend(); ++it)
        {
            if (it.value() == tracer->GetName())
            {
                _dialog->setCurrentMarkerIndex(it.key());
                break;
            }
        }
        _dialog->setExistMarkerMap(map);

        _dialog->initData({ tmp, nullptr });
        _dialog->ChangeCurrentWidget(0);
        _dialog->showWindow();
    }

    void LineChartWindow::slot_ChangeTracerProperty(int tracerID, int guideLineID)
    {
        Style2D_TracerProperty* tmp = nullptr;
        for (int i = 0; i < m_tracerPropertyWidget->rowCount(); ++i)
        {
            auto tracer = m_tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
            if (tracer->getTracerIndex() == tracerID)
            {
                tmp = tracer->getStyle2DTracerProperty();
                if (tmp == nullptr)
                    return;
                tracer->SetName(tmp->m_tracerName);
                tracer->setGraphKey(tmp->m_x);
                tracer->setStyle(QCPItemTracer::TracerStyle(tmp->m_symbolStyle + 1));
                tracer->setSize(tmp->m_symbolSize * 2);
                tracer->setPen(QPen(tmp->m_symbolColor));

                QString _pyCode = QString("PostProcessing.lineChartWindowChangeTracerProperty(%1, '%2', %3, %4, %5, '%6')")
                                      .arg(tracerID) //int
                                      .arg(tmp->m_tracerName) //QString
                                      .arg(tmp->m_x) //double
                                      .arg(tmp->m_symbolStyle) //int
                                      .arg(tmp->m_symbolSize) //double
                                      .arg(tmp->m_symbolColor.name().mid(1)); // QString
                emit IBaseSignalInstance->signal_execPYCode(QStringList{_pyCode}, true, false);

                break;
            }
        }

        m_customPlot->replot();
    }

    void LineChartWindow::slot_GuideLinePropertyShow(LineChartStraightLine* guideLine)
    {
        if (guideLine == nullptr)
        {
            return;
        }
        auto tmp = guideLine->getStyle2DGuideLineProperty();
        tmp->m_value = guideLine->GetValue();
        auto _dialog = new DialogTracer2DSettings(this);
        connect(_dialog, &DialogTracer2DSettings::signal_sendData, this, &LineChartWindow::slot_ChangeGuideLineProperty);
        _dialog->initData({ nullptr, tmp });
        _dialog->setGuideLineID(guideLine->getLineChartStraightLineID());
        _dialog->ChangeCurrentWidget(1);
        _dialog->showWindow();
    }

    void LineChartWindow::slot_ChangeGuideLineProperty(int tracerID, int guideLineID)
    {
        auto _tempGuideLine = m_customPlot->getLineChartStraightLineByID(guideLineID);
        auto tmp = _tempGuideLine->getStyle2DGuideLineProperty();
        if (_tempGuideLine == nullptr || tmp == nullptr)
        {
            return;
        }

        _tempGuideLine->SetValue(tmp->m_value);
        auto penLine = _tempGuideLine->pen();
        penLine.setStyle(Qt::PenStyle(tmp->m_guideLineStyle + 1));
        penLine.setWidthF(tmp->m_guideLineThickness);
        penLine.setColor(tmp->m_guideLineColor);
        _tempGuideLine->setPen(penLine);

        m_customPlot->replot();

        
        QString _pyCode = QString("PostProcessing.lineChartWindowChangeGuideLineProperty(%1, %2, %3, %4, '%5')")
                              .arg(guideLineID) //int
                              .arg(tmp->m_value) //double
                              .arg(tmp->m_guideLineStyle) //int
                              .arg(tmp->m_guideLineThickness) //double
                              .arg(tmp->m_guideLineColor.name().mid(1)); // QString
        emit IBaseSignalInstance->signal_execPYCode(QStringList{_pyCode}, true, false);

    }

    void LineChartWindow::slot_measureData(const QString& measureNama, double value)
    {
        bool isDoneOnece = false;
        auto graphList = m_customPlot->selectedGraphs();
        for (auto graph : graphList)
        {
            const auto& graphData = graph->data();
            bool findRange = false;
            auto range = graphData->valueRange(findRange);
            if (!findRange)
            {
                continue;
            }
            auto measureTableWidget = m_measureTableWidget;
            bool isExits = false;
            for (int i = 0; i < measureTableWidget->rowCount(); ++i)
            {
                auto t = measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
                if (t->GetLayerable() == graph && t->GetName() == measureNama)
                {
                    if (measureNama == "驻波带宽")
                    {
                        auto tTmp = static_cast<BeamBandwidthTracer*>(t);
                        // 驻波值相同，已存在，不添加
                        if (tTmp->GetStandingWwaveValue() == value)
                        {
                            isExits = true;
                            break;
                        }
                    }
                    else
                    {
                        isExits = true;
                        break;
                    }
                }
            }
            if (isExits)
            {
                EDialogMsgResult _result = IdaDialogMsg::showDialog(this, QString("%1上该测量已存在").arg(graph->name()), EDialogMsg::Warning, tr("测量提示"));
                continue;
            }
            if (measureTableWidget->isHidden())
            {
                QPoint p(0, 0);
                if (!m_tracerPropertyWidget->isHidden() && m_tracerPropertyWidget->geometry().x() < m_customPlot->axisRect()->topLeft().x() + 20)
                {
                    p.setX(m_tracerPropertyWidget->width() + 10);
                }
                measureTableWidget->move(m_customPlot->axisRect()->topLeft() + p + QPoint(10, 10));
                measureTableWidget->show();
            }
            isDoneOnece = true;
            LineChartTracer* tracer = nullptr;
            if (measureNama == "最大值")
            {
                tracer = new LineChartTracer(m_customPlot);
                tracer->SetName("最大值");
                tracer->setVisible(true);
            }
            else if (measureNama == "最小值")
            {
                tracer = new LineChartTracer(m_customPlot);
                tracer->SetName("最小值");
                tracer->setVisible(true);
            }
            else if (measureNama == "平均值")
            {
                tracer = new LineChartTracer(m_customPlot);
                tracer->SetName("平均值");
                tracer->setVisible(false);
            }
            else if (measureNama == "半功率波束带宽")
            {
                auto t = new BeamBandwidthTracer(m_customPlot);
                t->SetName("半功率波束带宽");
                t->setVisible(true);
                tracer = t;
            }
            else if (measureNama == "驻波带宽")
            {
                auto t = new BeamBandwidthTracer(m_customPlot);
                t->SetName("驻波带宽");
                t->setVisible(true);
                t->SetStandingWwaveValue(value);
                tracer = t;
            }
            for (auto _curveInfoPair : m_curveMap)
            {
                if (_curveInfoPair.second->getCurveLineAddress() == graph)
                {
                    tracer->setCurveInfoID(_curveInfoPair.second->getInformationID());
                }
            }
            tracer->SetLayerable(graph);
            measureTableWidget->AppendTracerProperty(tracer);
        }
        m_customPlot->replot();
        if (isDoneOnece)
        {
            slot_adaptiveRange();
        }
    }

    void LineChartWindow::slot_measureData(MeasureType type, double value)
    {
        slot_measureData(getMeasureTypeName(type), value);
    }

    void LineChartWindow::slot_smoothData(double range)
    {
        for (auto graph : m_customPlot->selectedGraphs())
        {
            QStandardItem* item = nullptr;
            Info2DPointer info = Info2DPointer::create();
            for (auto& curvePair : m_curveMap)
            {
                if (curvePair.second->getCurveLineAddress() == graph)
                {
                    if (getIsEdit())
                    {
                        info = curvePair.second;
                        item = curvePair.first;
                    }
                    else
                    {
                        info = Info2DPointer::create(*curvePair.second);
                        info->setIsFromStandardFile(false);
                    }
                }
            }
            const auto& graphData = graph->data();
            QList<QPair<QCPRange, QList<double>>> tmpList;
            for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
            {
                double key = iter->key;
                QCPRange keyRange(key * (1 - range / 2), key * (1 + range / 2));
                tmpList.append(qMakePair(keyRange, QList<double>()));
            }
            for (auto& tmp : tmpList)
            {
                for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
                {
                    double key = iter->key;
                    if (tmp.first.contains(key))
                    {
                        tmp.second.append(iter->value);
                    }
                }
            }
            auto yDataPointer = info->getYDataPointer();
            if (yDataPointer->second.size() != tmpList.size())
            {
                continue;
            }
            for (int i = 0; i < tmpList.size(); ++i)
            {
                double n = 0;
                for (double num : tmpList.at(i).second)
                {
                    n += num;
                }
                yDataPointer->second[i] = n / tmpList.at(i).second.size();
            }

            QString params = QString::number(DataAnalysisType::SmoothData) + "," + QString::number(range);
            if (getIsEdit())
            {
                item->setData(params, Qt::UserRole + 3);
                graph->setData(info->getXData().second, yDataPointer->second);
                info->setCurveLineAddress(graph);
                info->setIsNewData(true);
            }
            else
            {
                QString name = graph->name() + "_平滑" + "_" + QString::number(m_smoothId++);
                while (getHasSameName(name)) // 有重复的曲线名字,需要重新命名
                {
                    name += "_1";
                }

                yDataPointer->first = "平滑";
                QCPGraph* gta = m_customPlot->addGraph();
                auto index = m_graphs.size() % m_colorList.size();
                auto color = m_colorList.at(index);
                QPen pen;
                pen.setWidth(2);
                pen.setColor(color);
                gta->setPen(pen);
                m_graphs.append(gta);
                gta->setData(info->getXData().second, yDataPointer->second);
                gta->setName(name);
                info->setCurveLineAddress(gta);
                info->setIsNewData(true);
                info->setDataSources(QString());
                if (!GlobalHelperInstance->getIsOpenProject())
                {
                    info->setCurveName(name);
                    info->setInformationID(WindowTotalDataInstance->getGraph2DInformationMaxID());
                }
                WindowTotalDataInstance->appendInfomationCurve2DBasical(info);
                auto dataProperty = new Style2D_DataProperty(this);
                if (info->getXData().second.size() == 1)
                {
                    auto scatterStyle = gta->scatterStyle();
                    scatterStyle.setShape(QCPScatterStyle::ssDisc);
                    scatterStyle.setPen(color);
                    gta->setScatterStyle(scatterStyle);

                    dataProperty->m_isDisplaySymbol = true;
                    dataProperty->m_symbolStyle = 4;
                }
                dataProperty->m_resultDataName = name;
                dataProperty->m_dataLineColor = color;
                dataProperty->m_symbolColor = color;
                if (!GlobalHelperInstance->getIsOpenProject())
                {
                    m_centerSettingData->m_style2D_DataProperty = dataProperty;
                    info->setLineChartCenterSettingData(m_centerSettingData);
                    info->setCurvePropertyData(dataProperty);
                }
                // 添加曲线名字
                QStandardItem* item = m_settings->addCurveToList(name, params);
                // item->setCheckState(Qt::Checked);
                // m_curveMap[item] = info; // 记录下来以备查找
                addCurveItemInfoPair(item, info);
                m_addCurveInfo.append(info);
                info->setSidebarItem(item);
            }
        }
        m_customPlot->replot();
    }

    int LineChartWindow::slot_interpolationData(int number, InterpolationType type)
    {
        for (auto graph : m_customPlot->selectedGraphs())
        {
            Info2DPointer info = Info2DPointer::create();
            QStandardItem* item = nullptr;
            for (auto& curvePair : m_curveMap)
            {
                if (curvePair.second->getCurveLineAddress() == graph)
                {
                    if (getIsEdit())
                    {
                        info = curvePair.second;
                        item = curvePair.first;
                    }
                    else
                    {
                        info = Info2DPointer::create(*curvePair.second);
                        info->setIsFromStandardFile(false);
                    }
                }
            }
            QString _itemName{};
            QVector<double> xData, yData;
            const auto& graphData = graph->data();
            if (type == InterpolationType::linearInterpolation) // 线性插值
            {
                _itemName = QStringLiteral("_线性插值");
                linearInterpolationMethod(number, graphData, xData, yData);
            }
            else if (type == InterpolationType::logarithmicInterpolationSingleAxisX) // 单X轴对数插值
            {
                _itemName = QStringLiteral("_单X轴对数插值");
                auto ok = logarithmicInterpolationMethod(number, graphData, xData, yData, InterpolationType::logarithmicInterpolationSingleAxisX);
                if (!ok)
                {
                    return 1;
                }

            }
            else if (type == InterpolationType::logarithmicInterpolationSingleAxisY) // 单Y轴对数插值
            {
                _itemName = QStringLiteral("_单Y轴对数插值");
                auto ok = logarithmicInterpolationMethod(number, graphData, xData, yData, InterpolationType::logarithmicInterpolationSingleAxisY);
                if (!ok)
                {
                    return 2;
                }
            }
            else if (type == InterpolationType::logarithmicInterpolationDoubleAxis) // 双对数轴对数插值
            {
                _itemName = QStringLiteral("_双对数轴对数插值");
                auto ok = logarithmicInterpolationMethod(number, graphData, xData, yData, InterpolationType::logarithmicInterpolationDoubleAxis);
                if (!ok)
                {
                    return 3;
                }
            }
            else if (type == InterpolationType::splineInterpolation) // 样条插值
            {
                _itemName = QStringLiteral("_样条插值");
            }
            else if (type == InterpolationType::polynomialInterpolation) // 多项式插值
            {
                _itemName = QStringLiteral("_多项式插值");
            }
            else
                return -1;
            info->getXDataPointer()->second = std::move(xData);
            auto yDataPointer = info->getYDataPointer();
            yDataPointer->second = std::move(yData);

            QString params;
            switch (type)
            {
            case pst::InterpolationType::linearInterpolation:
                params = QString::number(DataAnalysisType::Interpolation) + "," + QString::number(number);
                break;
            case pst::InterpolationType::logarithmicInterpolationSingleAxisX:
                params = QString::number(DataAnalysisType::InterpolationSingleAxisX) + "," + QString::number(number);
                break;
            case pst::InterpolationType::logarithmicInterpolationSingleAxisY:
                params = QString::number(DataAnalysisType::InterpolationSingleAxisY) + "," + QString::number(number);
                break;
            case pst::InterpolationType::logarithmicInterpolationDoubleAxis:
                params = QString::number(DataAnalysisType::InterpolationDoubleAxis) + "," + QString::number(number);
                break;
            case pst::InterpolationType::splineInterpolation:
                break;
            case pst::InterpolationType::polynomialInterpolation:
                break;
            default:
                break;
            }
            if (getIsEdit())
            {
                graph->setData(info->getXData().second, yDataPointer->second);
                info->setCurveLineAddress(graph);
                info->setIsNewData(true);
                item->setData(params, Qt::UserRole + 3);
            }
            else
            {
                QString name = graph->name() + _itemName + "_" + QString::number(m_interpolateId++);
                while (getHasSameName(name)) // 有重复的曲线名字,需要重新命名
                {
                    name += "_1";
                }

                yDataPointer->first = _itemName.remove(0, 1);
                QCPGraph* gta = m_customPlot->addGraph();
                auto index = m_graphs.size() % m_colorList.size();
                auto& color = m_colorList.at(index);
                QPen pen;
                pen.setWidth(2);
                pen.setColor(color);
                gta->setPen(pen);
                m_graphs.append(gta);
                gta->setData(info->getXData().second, yDataPointer->second);
                gta->setName(name);
                info->setCurveLineAddress(gta);
                info->setIsNewData(true);
                info->setDataSources(QString());
                if (!GlobalHelperInstance->getIsOpenProject())
                {
                    info->setCurveName(name);
                    info->setInformationID(WindowTotalDataInstance->getGraph2DInformationMaxID());
                }
                WindowTotalDataInstance->appendInfomationCurve2DBasical(info);
                auto dataProperty = new Style2D_DataProperty(this);
                if (info->getXData().second.size() == 1)
                {
                    auto scatterStyle = gta->scatterStyle();
                    scatterStyle.setShape(QCPScatterStyle::ssDisc);
                    scatterStyle.setPen(color);
                    gta->setScatterStyle(scatterStyle);

                    dataProperty->m_isDisplaySymbol = true;
                    dataProperty->m_symbolStyle = 4;
                }
                dataProperty->m_dataLineColor = color;
                dataProperty->m_symbolColor = color;
                dataProperty->m_resultDataName = name;
                if (!GlobalHelperInstance->getIsOpenProject())
                {
                    m_centerSettingData->m_style2D_DataProperty = dataProperty;
                    info->setLineChartCenterSettingData(m_centerSettingData);
                    info->setCurvePropertyData(dataProperty);
                }
                // 添加曲线名字
                QStandardItem* item = m_settings->addCurveToList(name, params);
                // item->setCheckState(Qt::Checked);
                // m_curveMap[item] = info; // 记录下来以备查找
                addCurveItemInfoPair(item, info);
                m_addCurveInfo.append(info);
                info->setSidebarItem(item);
            }
        }
        m_customPlot->replot();
        return 0;
    }

    void LineChartWindow::linearInterpolationMethod(int number, QSharedPointer<QCPGraphDataContainer> graphData, QVector<double>& xData, QVector<double>& yData)
    {
        auto iter = graphData->begin();
        ++iter;
        for (iter; iter != graphData->end(); ++iter)
        {
            auto it = iter;
            const auto previousIter = --it; // 前一个原始数据点
            const auto nextIter = iter;     // 后一个原始数据点
            int endIndex = number + 1;
            it = iter;
            ++it;
            if (it == graphData->end())
            {
                ++endIndex;
            }
            double k = (nextIter->value - previousIter->value) / (nextIter->key - previousIter->key);
            for (int i = 0; i < endIndex; ++i)
            {
                double key = previousIter->key + i / (number + 1.0) * (nextIter->key - previousIter->key);
                double value = previousIter->value + k * (key - previousIter->key);
                xData.append(key);
                yData.append(value);
            }
        }
    }

    bool LineChartWindow::logarithmicInterpolationMethod(int number, QSharedPointer<QCPGraphDataContainer> graphData, QVector<double>& xData, QVector<double>& yData, InterpolationType type)
    {
        QVector<QPair<double, double>> _originalDataLog10{};
        double keyLog10 = 0.0;
        double valueLog10 = 0.0;
        auto iter = graphData->begin();
        for (iter; iter != graphData->end(); ++iter)
        {
            if (type == InterpolationType::logarithmicInterpolationSingleAxisX || type == InterpolationType::logarithmicInterpolationDoubleAxis)
            {
                if (iter->key < 0) // x小于0不能单X轴对数插值
                    return false;
                if (qFuzzyCompare(0, iter->key))
                {
                    iter->key += 0.000001;
                }
                keyLog10 = std::log10(iter->key);
            }
            if (type == InterpolationType::logarithmicInterpolationSingleAxisY || type == InterpolationType::logarithmicInterpolationDoubleAxis)
            {
                if (iter->value < 0) // y小于0不能单Y轴对数插值
                    return false;
                if (qFuzzyCompare(0, iter->value))
                {
                    iter->value += 0.000001;
                }
                valueLog10 = std::log10(iter->value);
            }

            if (type == InterpolationType::logarithmicInterpolationSingleAxisX)
            {
                _originalDataLog10.append(qMakePair(keyLog10, iter->value));
            }
            else if (type == InterpolationType::logarithmicInterpolationSingleAxisY)
            {
                _originalDataLog10.append(qMakePair(iter->key, valueLog10));
            }
            else if (type == InterpolationType::logarithmicInterpolationDoubleAxis)
            {
                _originalDataLog10.append(qMakePair(keyLog10, valueLog10));
            }
        }

        auto iter1 = _originalDataLog10.begin();
        ++iter1;
        for (iter1; iter1 != _originalDataLog10.end(); ++iter1)
        {
            auto it1 = iter1;
            const auto previousIter1 = --it1; // 前一个原始数据点
            const auto nextIter1 = iter1;     // 后一个原始数据点
            int endIndex1 = number + 1;
            it1 = iter1;
            ++it1;
            if (it1 == _originalDataLog10.end())
            {
                ++endIndex1;
            }
            double k = (nextIter1->second - previousIter1->second) / (nextIter1->first - previousIter1->first);
            for (int i = 0; i < endIndex1; ++i)
            {
                double key = previousIter1->first + i / (number + 1.0) * (nextIter1->first - previousIter1->first);
                double value = previousIter1->second + k * (key - previousIter1->first);

                if (type == InterpolationType::logarithmicInterpolationSingleAxisX)
                {
                    xData.append(std::pow(10, key));
                    yData.append(value);
                }
                else if (type == InterpolationType::logarithmicInterpolationSingleAxisY)
                {
                    xData.append(key);
                    yData.append(std::pow(10, value));
                }
                else if (type == InterpolationType::logarithmicInterpolationDoubleAxis)
                {
                    xData.append(std::pow(10, key));
                    yData.append(std::pow(10, value));
                }
            }
        }

        return true;
    }

    QList<LineChartTracer*> LineChartWindow::getAllTracers(QCustomPlot* customPlot)
    {
        return customPlot->findChildren<LineChartTracer*>();
    }

    bool LineChartWindow::doUnitConversion(const Info2DPointer& info)
    {
        return false;
    }

    bool LineChartWindow::doUnitConversion(const QString& oldUnit, const QString& newUnit, QList<double>& value)
    {
        // UnitHelper::doKeyUnitConvert();
        return false;
    }

    void LineChartWindow::initCoordinateSystem()
    {
        // todo 根据坐标系数据初始化坐标系 m_coordinateSetting

    }

    bool LineChartWindow::getHasSameName(const QString& name)
    {
        auto model = m_settings->getCurveNameListView()->model();
        for (int row = 0; row < model->rowCount(); ++row)
        {
            QModelIndex index = model->index(row, 0);                          // 获取模型中的每一行
            QString itemName = model->data(index, Qt::DisplayRole).toString(); // 获取显示角色的数据
            if (itemName == name)
            {
                return true;
            }
        }
        return false;
    }


    // 把 previewTracer 的原子属性序列化到 QStringList
    QString LineChartWindow::serializeTracer(QCPItemTracer* previewTracer,
        QCustomPlot* customPlot, QString markerName, int setCurveInfoID,int tracerIndex)
    {
        QStringList sl;

        // 基本开关、枚举、数值
        sl << QString::number(previewTracer->interpolating());
        sl << QString::number(static_cast<int>(previewTracer->style()));
        sl << QString::number(previewTracer->size());
        sl << QString::number(previewTracer->graphKey());
        sl << QString::number(previewTracer->visible());

        // Pen
        QPen pen = previewTracer->pen();
        //sl << pen.color().name();             // "#RRGGBB"
        sl << QString::number(pen.widthF());
        sl << QString::number(static_cast<int>(pen.style()));
        sl << QString::number(pen.color().red());
        sl << QString::number(pen.color().green());
        sl << QString::number(pen.color().blue());

        // Brush
        QBrush brush = previewTracer->brush();
        //sl << brush.color().name();
        sl << QString::number(static_cast<int>(brush.style()));
        sl << QString::number(brush.color().red());
        sl << QString::number(brush.color().green());
        sl << QString::number(brush.color().blue());

        // info ID
        int infoId = -1;
        for (auto i : m_curveMap)
        {
            if (i.second->getCurveLineAddress() == previewTracer->graph())
            {
                infoId = i.second->getInformationID();
                break;
            }
        }
        sl << QString::number(infoId);

        // 坐标
        auto* pos = previewTracer->position;
        sl << QString::number(pos->coords().x(), 'g', 15);
        sl << QString::number(pos->coords().y(), 'g', 15);

        sl << markerName;
        sl << QString::number(setCurveInfoID);
        sl << QString::number(tracerIndex);

        QString sep = "||";
        QString packed = sl.join(sep);
        return packed;
    }

    // 用返回的 QStringList 重建一个新的 LineChartTracer
    void LineChartWindow::importTracerFromList(const QString& sl1,
        QCustomPlot* customPlot, LineChartTracer* tracer)
    {
        QString sep = "||";
        QStringList sl = sl1.split(sep, QString::KeepEmptyParts);

        int idx = 0;
        bool interpolating = sl[idx++].toInt();
        auto style = static_cast<QCPItemTracer::TracerStyle>(sl[idx++].toInt());
        double size = sl[idx++].toDouble();
        double graphKey = sl[idx++].toDouble();
        bool visible = sl[idx++].toInt();

        QPen pen;
        pen.setWidthF(sl[idx++].toDouble());
        pen.setStyle(static_cast<Qt::PenStyle>(sl[idx++].toInt()));
        QColor penColor;
        penColor.setRed(sl[idx++].toInt());
        penColor.setGreen(sl[idx++].toInt());
        penColor.setBlue(sl[idx++].toInt());
        pen.setColor(penColor);

        //Brush
        QBrush brush;

        brush.setStyle(static_cast<Qt::BrushStyle>(sl[idx++].toInt()));
        QColor brushColor;
        brushColor.setRed(sl[idx++].toInt());
        brushColor.setGreen(sl[idx++].toInt());
        brushColor.setBlue(sl[idx++].toInt());
        brush.setColor(penColor);

        //info ID
        int infoId = sl[idx++].toInt();

        double x = sl[idx++].toDouble();
        double y = sl[idx++].toDouble();

        QString markerName = sl[idx++];
        int setCurveInfoID = sl[idx++].toInt();
        int tracerIndex = sl[idx++].toInt();

        // 真正重建
        //auto tracer = new LineChartTracer(customPlot);
        tracer->setInterpolating(interpolating);
        tracer->setStyle(style);
        tracer->setSize(size);
        tracer->setGraphKey(graphKey);
        tracer->setVisible(visible);
        tracer->setPen(pen);
        tracer->setBrush(brush);
        
        qDebug() << pen.color();
        qDebug() << brush.color();


        int graphIndex = -1;
        for (auto i : m_curveMap)
        {
            if (i.second->getInformationID() == infoId)
            {
                tracer->setGraph(qobject_cast<QCPGraph*>(i.second->getCurveLineAddress()));
                break;
            }
        }
  
        tracer->position->setCoords(x, y);
        tracer->updatePosition();

        tracer->SetName(markerName);
        tracer->setCurveInfoID(setCurveInfoID);
        tracer->setTracerIndex(tracerIndex);

        //customPlot->replot();
    }

    void LineChartWindow::slot_updateBeamBandwidthProperty()
    {
        if (m_measureTableWidget->isHidden())
        {
            return;
        }
        QStringList errorList;
        for (int i = 0; i < m_measureTableWidget->rowCount(); ++i)
        {
            auto tracer = m_measureTableWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
            auto graph = qobject_cast<QCPGraph*>(tracer->GetLayerable());
            if (graph == nullptr)
            {
                continue;
            }
            const auto& graphData = graph->data();
            bool findRange = false;
            auto range = graphData->valueRange(findRange);
            std::set<double> maxKeySet;
            double value = 0;
            if (!findRange)
            {
                continue;
            }
            if (tracer->GetName() != "半功率波束带宽")
            {
                continue;
            }
            auto isVisible = tracer->GetLabel()->visible();
            tracer->setVisible(graph->visible());
            if (!tracer->visible())
            {
                continue;
            }
            bool isDb = false;
            for (auto curvePair : m_curveMap)
            {
                auto& info = curvePair.second;
                if (info->getCurveLineAddress() == graph)
                {
                    isDb = info->getIsDB();
                    break;
                }
            }
            if (isDb)
            {
                value = range.upper - 3;
            }
            else
            {
                value = range.upper * 0.707;
            }
            if (!range.contains(value))
            {
                tracer->setVisible(false);
                tracer->setMeasurementConditionsIsSatisfied(false);
                // if (isVisible)
                //{
                //     errorList.append(QString("%1不满足半功率波束带宽测量条件").arg(graph->name()));
                // }
                continue;
            }
            else
                tracer->setMeasurementConditionsIsSatisfied(true);
            for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
            {
                if (iter->value == range.upper)
                {
                    maxKeySet.insert(iter->key);
                }
            }
            QVector<QPair<QCPRange, QCPRange>> rangeArray;
            for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
            {
                const auto& previousIter = iter; // 前一个原始数据点
                const auto& nextIter = iter + 1; // 后一个原始数据点
                QCPRange keyRange, valueRange;
                if (nextIter != graphData->end())
                {
                    keyRange.lower = previousIter->key;
                    keyRange.upper = nextIter->key;
                    valueRange.lower = previousIter->value;
                    valueRange.upper = nextIter->value;
                }
                else
                {
                    keyRange.upper = keyRange.lower = previousIter->key;
                    valueRange.upper = valueRange.lower = previousIter->value;
                }
                bool isContains = false;
                if (valueRange.lower > valueRange.upper)
                {
                    if (value >= valueRange.upper && value <= valueRange.lower)
                    {
                        isContains = true;
                    }
                }
                else
                {
                    if (value >= valueRange.lower && value <= valueRange.upper)
                    {
                        isContains = true;
                    }
                }
                if (isContains)
                {
                    rangeArray.append(qMakePair(keyRange, valueRange));
                }
            }
            std::set<double> keySet;
            for (int j = 0; j < rangeArray.size(); ++j)
            {
                auto& range = rangeArray.at(j);
                double key = std::numeric_limits<double>::quiet_NaN();
                if (range.first.upper == range.first.lower)
                {
                    key = range.second.lower;
                }
                else
                {
                    double k = (range.second.upper - range.second.lower) / (range.first.upper - range.first.lower);
                    key = range.first.lower + (value - range.second.lower) / k;
                }
                if (std::isnan(key))
                {
                    continue;
                }
                else
                {
                    keySet.insert(key);
                }
            }
            if (keySet.size() < 2)
            {
                tracer->setVisible(false);
                tracer->setMeasurementConditionsIsSatisfied(false);
                // if (isVisible)
                //{
                //     errorList.append(QString("%1不满足半功率波束带宽测量条件").arg(graph->name()));
                // }
                continue;
            }
            else
                tracer->setMeasurementConditionsIsSatisfied(true);
            bool isContains = false;
            for (double maxKey : maxKeySet)
            {
                // auto iter = keySet.begin();
                //++iter;
                for (auto iter = ++keySet.begin(); iter != keySet.end(); ++iter)
                {
                    auto it = iter;
                    const auto& previousIter = --it; // 前一个原始数据点
                    const auto& nextIter = iter;     // 后一个原始数据点
                    if (*previousIter < maxKey && *nextIter > maxKey)
                    {
                        auto indeicator = qobject_cast<BeamBandwidthTracer*>(tracer)->GetIndicator();
                        indeicator->start->setCoords(*previousIter, value);
                        indeicator->end->setCoords(*nextIter, value);
                        tracer->position->setCoords((*previousIter + *nextIter) / 2, value);
                        isContains = true;
                        break;
                    }
                }
            }
            if (!isContains)
            {
                tracer->setVisible(false);
                tracer->setMeasurementConditionsIsSatisfied(false);
                // if (isVisible)
                //{
                //     errorList.append(QString("%1不满足半功率波束带宽测量条件").arg(graph->name()));
                // }
            }
            else
                tracer->setMeasurementConditionsIsSatisfied(true);
        }
        // if (!errorList.isEmpty())
        //{
        //     EDialogMsgResult _result = IdaDialogMsg::showDialog(this, errorList.join("\n"), EDialogMsg::Error, tr("半功率波束带宽错误列表"));
        // }
    }

    void LineChartWindow::slot_updateStandingWaveBandwidthProperty()
    {
        if (m_measureTableWidget->isHidden())
        {
            return;
        }
        QHash<QPair<QCPGraph*, double>, QVector<BeamBandwidthTracer*>> standingWaveBandwidths;
        for (int i = 0; i < m_measureTableWidget->rowCount(); ++i)
        {
            auto tracer = m_measureTableWidget->item(i, 0)->data(QVariant::UserType).value<BeamBandwidthTracer*>();
            if (tracer == nullptr)
            {
                continue;
            }
            auto graph = qobject_cast<QCPGraph*>(tracer->GetLayerable());
            if (graph == nullptr)
            {
                continue;
            }
            if (tracer->GetName() != "驻波带宽")
            {
                continue;
            }
            auto isVisible = tracer->GetLabel()->visible();
            if (!graph->visible())
            {
                tracer->setVisible(graph->visible());
                continue;
            }
            auto pair = qMakePair(graph, tracer->GetStandingWwaveValue());
            if (standingWaveBandwidths.contains(pair))
            {
                standingWaveBandwidths[pair].append(tracer);
            }
            else
            {
                standingWaveBandwidths.insert(pair, { tracer });
            }
        }
        QStringList errorList;
        QList<LineChartTracer*> removeTracers;
        for (auto iter = standingWaveBandwidths.begin(); iter != standingWaveBandwidths.end(); ++iter)
        {
            const auto& key = iter.key();
            const auto& graph = key.first;
            double y_value = key.second;
            const auto& graphData = graph->data();
            QVector<QPair<QCPRange, QCPRange>> rangeArray;
            for (auto i = graphData->begin(); i != graphData->end(); ++i)
            {
                const auto& previousIter = i; // 前一个原始数据点
                const auto& nextIter = i + 1; // 后一个原始数据点
                QCPRange keyRange, valueRange;
                if (nextIter != graphData->end())
                {
                    keyRange.lower = previousIter->key;
                    keyRange.upper = nextIter->key;
                    valueRange.lower = previousIter->value;
                    valueRange.upper = nextIter->value;
                }
                else
                {
                    if (previousIter != graphData->begin())
                    {
                        const auto& previousIterTmp = i - 1; // 前一个原始数据点
                        keyRange.lower = previousIterTmp->key;
                        keyRange.upper = previousIter->key;
                        valueRange.lower = previousIterTmp->value;
                        valueRange.upper = previousIter->value;
                    }
                    else
                    {
                        keyRange.upper = keyRange.lower = previousIter->key;
                        valueRange.upper = valueRange.lower = previousIter->value;
                    }
                }
                bool isContains = false;
                if (valueRange.lower > valueRange.upper)
                {
                    if (y_value >= valueRange.upper && y_value <= valueRange.lower)
                    {
                        isContains = true;
                    }
                }
                else
                {
                    if (y_value >= valueRange.lower && y_value <= valueRange.upper)
                    {
                        isContains = true;
                    }
                }
                if (isContains)
                {
                    rangeArray.append(qMakePair(keyRange, valueRange));
                }
            }
            QList<QPair<double, double>> datas;
            for (int j = 0; j < rangeArray.size(); ++j)
            {
                const auto& range = rangeArray.at(j);
                double value = std::numeric_limits<double>::quiet_NaN();
                double k = 0;
                if (range.first.upper != range.first.lower)
                {
                    k = (range.second.upper - range.second.lower) / (range.first.upper - range.first.lower);
                    value = range.first.lower + (y_value - range.second.lower) / k;
                }
                if (k != 0 && !std::isnan(value))
                {
                    datas.append(qMakePair(k, value));
                }
            }
            int index = 0;
            const auto& tracers = iter.value();
            for (int i = 1; i < datas.size(); ++i)
            {
                const auto& previous = datas.at(i - 1);
                const auto& next = datas.at(i);
                if (previous.first < 0 && next.first > 0)
                {
                    BeamBandwidthTracer* tracer = nullptr;
                    if (index < tracers.size())
                    {
                        tracer = tracers.at(index);
                    }
                    // 出现多的满足条件情况，新增该驻波值的标记
                    else
                    {
                        tracer = new BeamBandwidthTracer(m_customPlot);
                        tracer->SetName("驻波带宽");
                        tracer->setVisible(true);
                        tracer->SetLayerable(graph);
                        for (auto _curveInfoPair : m_curveMap)
                        {
                            if (_curveInfoPair.second->getCurveLineAddress() == graph)
                            {
                                tracer->setCurveInfoID(_curveInfoPair.second->getInformationID());
                            }
                        }
                        tracer->SetStandingWwaveValue(y_value);
                        m_measureTableWidget->AppendTracerProperty(tracer);
                    }
                    if (tracer == nullptr)
                    {
                        continue;
                    }
                    ++index;
                    tracer->setVisible(true);
                    tracer->setMeasurementConditionsIsSatisfied(true);
                    auto indeicator = qobject_cast<BeamBandwidthTracer*>(tracer)->GetIndicator();
                    indeicator->start->setCoords(previous.second, y_value);
                    indeicator->end->setCoords(next.second, y_value);
                    tracer->position->setCoords((previous.second + next.second) / 2, y_value);
                }
            }
            bool isChange = false;
            // 满足条件情况变少，删除该驻波值多余的标记
            for (int i = index; i < tracers.size(); ++i)
            {
                if (i > 0)
                {
                    removeTracers.append(tracers.at(i));
                    continue;
                }
                if (tracers.at(i)->visible())
                {
                    isChange = true;
                }
                tracers.at(i)->setVisible(false);
                tracers.at(i)->setMeasurementConditionsIsSatisfied(false);
            }
            if (isChange && index == 0)
            {
                errorList.append(QString("%1不满足驻波带宽值%2测量条件").arg(graph->name()).arg(y_value));
            }
        }
        slot_removeSelectedTracer(removeTracers);
        if (!errorList.isEmpty())
        {
             IdaDialogMsg::showDialog(this, errorList.join("\n"), EDialogMsg::Warning, tr("驻波带宽警告列表"));
        }
    }

    void LineChartWindow::slot_getCurveNames(QStringList& names)
    {
        names = GetCurveNames();
    }

    void LineChartWindow::slot_calculationCheck(const Info2DPointer& info, bool& isSuccess)
    {
        auto yData = info->getYData();

        auto reader = info->getReader();
        int index = reader->getRealValueIndex(info->getValueIndex(), info->getValueComponent());
        auto table = reader->getOriginalTable();
        if (index < 0 || index >= reader->getEachColUnitOfValue().size())
        {
            index = 0;
        }
        auto array = table->GetColumn(index + reader->getEachColNameOfKey().size());
        TextArrayMetaStruct metaStruct;
        TextArrayMetaHander::getArrayMeta(array, metaStruct);
        bool isPower = false;
        switch (metaStruct.resultParaType)
        {
        case 7:
        case 13:
        case 16:
        case 17:
        case 18:
            isPower = true;
            break;
        default:
            break;
        }

        // TODO 取对数和归一化 针对单条曲线
        normalizeAndLog(yData.second, info->getIsNormalized(), info->getIsDB(), isPower);
        auto calculationFormula = info->getCalculationFormula();
        auto resultData = compute(AnalyzeFormulaString(calculationFormula), qMakePair(yData.second, info->getXData().second));
        if (!resultData.first.isEmpty())
        {
            isSuccess = true;
        }
        else
        {
            isSuccess = false;
        }
    }

    void LineChartWindow::slot_addStandardCcurve(Info2DPointer& info)
    {
        auto reader = info->getReader();
        auto xArray = reader->getStandardTable()->GetColumn(info->getScanParameterIndex());
        TextArrayMetaStruct xArrayMetaStruct;
        TextArrayMetaHander::getArrayMeta(xArray, xArrayMetaStruct);
        auto xUnitType = xArrayMetaStruct.resultParaType;
        auto xUnit = xArrayMetaStruct.unit;
        info->m_xAxisType = xUnitType;
        info->m_xAxisUnit = xUnit;

        auto keyCloNum = reader->getEachColNameOfKey().size();
        int groupId = info->getValueIndex();
        int componentId = info->getValueComponent();
        int realValueIndex = reader->getRealValueIndex(groupId, componentId);
        auto yArray = reader->getStandardTable()->GetColumn(keyCloNum + realValueIndex);
        TextArrayMetaStruct yArrayMetaStruct;
        TextArrayMetaHander::getArrayMeta(yArray, yArrayMetaStruct);
        auto yUnitType = yArrayMetaStruct.resultParaType;
        auto yUnit = yArrayMetaStruct.unit;
        auto componentType = yArrayMetaStruct.resultDataType;
        auto& infoYUnit = info->m_yAxisUnit;
        std::get<0>(infoYUnit) = yUnitType;
        std::get<1>(infoYUnit) = componentType;
        std::get<2>(infoYUnit) = yUnit;


        int index = 1;
        const auto& name = reader->getEachColGroupNameOfValue().at(info->getValueIndex());
        if (m_standardCcurveNumber.contains(name))
        {
            index = m_standardCcurveNumber[name]++;
        }
        else
        {
            m_standardCcurveNumber.insert(name, index + 1);
        }

        QString incrementName = autoIncrementName("标准曲线_" + name);
        info->setDataSources("");
        info->setCurveName(incrementName);
        info->setIsFromStandardFile(true);
        addNewGraph(info);
        m_addCurveInfo.append(info);
    }

    void LineChartWindow::slot_totalCalculation(const QStringList& xNameList, const QStringList& yNameList, const QStringList& zNameList)
    {
        auto func = [this](const QStringList& graphNameList)
            {
                QVector<CalculationData> powerVector;
                auto dataList = GetCurveDataByNames(graphNameList);
                for (const auto& data : dataList)
                {
                    if (data.first.isEmpty())
                    {
                        continue;
                    }
                    if (graphNameList.size() == 1)
                    {
                        return data;
                    }
                    CalculationData tmp;
                    if (Power({ data, CalculationData({2}, {}) }, tmp))
                    {
                        powerVector.append(std::move(tmp));
                    }
                    else
                    {
                        return CalculationData();
                    }
                }
                CalculationData sum;
                if (powerVector.size() == 1)
                {
                    sum = powerVector.first();
                }
                else if (!Add(powerVector, sum))
                {
                    return CalculationData();
                }
                CalculationData total;
                if (!Sqrt({ sum }, total))
                {
                    return CalculationData();
                }
                if (total.second.isEmpty() || total.first.size() != total.second.size())
                {
                    return CalculationData();
                }
                return total;
            };
        auto func2 = [this](const QStringList& graphNameList, const QString& nameStr, CalculationData data, QList<QCPGraph*>& graphList)
            {
                Info2DPointer info = Info2DPointer::create();
                for (auto curvePair : m_curveMap)
                {
                    auto& infoTmp = curvePair.second;
                    QCPGraph* graph = qobject_cast<QCPGraph*>(infoTmp->getCurveLineAddress());
                    if (graphNameList.contains(graph->name()))
                    {
                        if (info->getCurveLineAddress() == nullptr)
                        {
                            info = Info2DPointer::create(*infoTmp);
                        }
                        graphList.append(graph);
                    }
                }
                info->getXDataPointer()->second = std::move(data.second);
                info->getYDataPointer()->second = std::move(data.first);
                info->getYDataPointer()->first = nameStr;
                info->setCurveName(nameStr);
                info->setIsNewData(true);
                info->setIsOnlyShow(true);
                info->setValueIndex(0);
                info->setGraph(this);
                info->setDataSources(QString());
                return info;
            };

        if (xNameList.isEmpty() && yNameList.isEmpty() && zNameList.isEmpty())
        {
            EDialogMsgResult _result = IdaDialogMsg::showDialog(this, "无线条计算", EDialogMsg::Error, tr("总量计算"));
            return;
        }
        auto EX = func(xNameList);
        auto EY = func(yNameList);
        auto EZ = func(zNameList);
        QList<QCPGraph*> xGraphList, yGraphList, zGraphList, totalGraphList;
        auto infoEX = func2(xNameList, "EX分量", EX, xGraphList);
        auto infoEY = func2(yNameList, "EY分量", EY, yGraphList);
        auto infoEZ = func2(zNameList, "EZ分量", EZ, zGraphList);
        slot_removeGraphs({ "EX分量" });
        slot_removeGraphs({ "EY分量" });
        slot_removeGraphs({ "EZ分量" });
        if (infoEX->getReader() != nullptr)
        {
            this->addNewGraph(infoEX);
        }
        if (infoEY->getReader() != nullptr)
        {
            this->addNewGraph(infoEY);
        }
        if (infoEZ->getReader() != nullptr)
        {
            this->addNewGraph(infoEZ);
        }
        auto total = func({ "EX分量", "EY分量", "EZ分量" });
        auto infoTotal = func2({ "EX分量", "EY分量", "EZ分量" }, "E总量", total, totalGraphList);
        slot_removeGraphs({ "E总量" });
        if (infoTotal->getReader() != nullptr)
        {
            this->addNewGraph(infoTotal);
        }
        slot_removeGraphs(xGraphList);
        slot_removeGraphs(yGraphList);
        slot_removeGraphs(zGraphList);
    }

    bool LineChartWindow::slot_computeHIRF(const QStringList& graphNameList, double incidentWaveFieldValue, TextFileParser* textFileParser, const QString& typeName, bool isCheckBoxChecked)
    {
        // QVector<CalculationData> powerVector;
        // for (const auto& graphName : graphNameList)
        //{
        //     auto data = GetCurveData(graphName, CalculationData());
        //     if (data.first.isEmpty())
        //     {
        //         continue;
        //     }
        //     CalculationData tmp;
        //     if (Power({data, CalculationData({2}, {})}, tmp))
        //     {
        //         powerVector.append(std::move(tmp));
        //     }
        //     else
        //     {
        //         return;
        //     }
        // }
        // CalculationData sum;
        // if (powerVector.size() == 1)
        //{
        //     sum = powerVector.first();
        // }
        // else if (!Add(powerVector, sum))
        //{
        //     return;
        // }
        // CalculationData total;
        // if (!Sqrt({sum}, total))
        //{
        //     return;
        // }
        // if (total.second.isEmpty() || total.first.size() != total.second.size())
        //{
        //     return;
        // }
        Info2DPointer newInfo = nullptr;
        Info2DPointer dataInfo1 = nullptr;
        Info2DPointer dataInfo2 = nullptr;
        QString curveName1;
        QString curveName2;
        QStandardItem* item1 = nullptr;
        QStandardItem* item2 = nullptr;

        if (!getIsEdit())
        {
            newInfo = Info2DPointer::create();
            for (auto curvePair : m_curveMap)
            {
                auto& infoTmp = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(infoTmp->getCurveLineAddress());
                if (graphNameList.contains(graph->name()))
                {
                    if (newInfo->getCurveLineAddress() == nullptr)
                    {
                        newInfo = Info2DPointer::create(*infoTmp);
                        break;
                    }
                }
            }
            if (newInfo->getCurveLineAddress() == nullptr)
            {
                return false;
            }
        }
        else
        {
            for (size_t i = 0; i < m_curveMap.size(); i++)
            {
                auto item = m_curveMap[i].first;
                auto& dataInfo = m_curveMap[i].second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(dataInfo->getCurveLineAddress());
                if (graph->selected())
                {
                    if (m_curveMap[i - 1].first->data(Qt::UserRole + 3).toString() == item->data(Qt::UserRole + 3).toString()) // 如果点击第二条折线做编辑
                    {
                        item1 = m_curveMap[i - 1].first;
                        item2 = m_curveMap[i].first;
                        dataInfo1 = m_curveMap[i - 1].second;
                        dataInfo2 = m_curveMap[i].second;
                        curveName1 = qobject_cast<QCPGraph*>(dataInfo1->getCurveLineAddress())->name();
                        curveName2 = graph->name();
                    }
                    else // 点击第一条
                    {
                        item1 = m_curveMap[i].first;
                        item2 = m_curveMap[i + 1].first;
                        dataInfo1 = m_curveMap[i].second;
                        dataInfo2 = m_curveMap[i + 1].second;
                        curveName1 = graph->name();
                        curveName2 = qobject_cast<QCPGraph*>(dataInfo2->getCurveLineAddress())->name();
                    }
                    break;
                }
            }
            QString params = QString::number(DataAnalysisType::HIRF) + "," 
                + graphNameList.join(",") + ","
                + QString::number(incidentWaveFieldValue) + "," 
                + typeName + ","
                + QFileInfo(textFileParser->GetFileName()).completeBaseName() + ","
                + QString::number(isCheckBoxChecked);
            item1->setData(params, Qt::UserRole + 3);
            item2->setData(params, Qt::UserRole + 3);
        }

        CalculationData total;
        total = GetCurveData(graphNameList.first(), CalculationData());
        textFileParser->setScanParameterIndex(0);
        QVector<QVector<double>> tmp;
        for (int i = 1; i < textFileParser->getEachColNameOfKey().size(); ++i)
        {
            tmp.append(QVector<double>(1, 0));
        }
        textFileParser->setOtherKeyParameter(tmp);
        QList<Info2DPointer> yList;
        if (textFileParser->getEachColNameOfValue().size() == 1)
        {
            textFileParser->getChosenLinesFromKey(QList<QPair<int, int>>{{0, 0}}, yList);
        }
        else
        {
            textFileParser->getChosenLinesFromKey(QList<QPair<int, int>>{{0, 0}, { 1, 0 }}, yList);
        }
        if (('[' + textFileParser->getEachColUnitOfKey().at(textFileParser->getScanParameterIndex()) + ']') != m_unit)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("变量类型或单位不一致！"), EDialogMsg::Error, QStringLiteral("添加错误"));
            return false;
        }
        for (size_t i = 0; i < yList.size(); i++)
        {
            auto& info = yList[i];
            QSharedPointer<QCPGraphDataContainer> graphData = QSharedPointer<QCPGraphDataContainer>::create();
            QVector<QCPGraphData> t;
            t.reserve(total.second.size());
            for (int i = 0; i < total.second.size(); ++i)
            {
                t.append(QCPGraphData(total.second.at(i), total.first.at(i)));
            }
            graphData->set(t, true);
            std::set set(total.second.begin(), total.second.end());
            auto minMax = std::minmax_element(total.second.begin(), total.second.end());

            const auto& xData = info->getXData().second;
            const auto& yData = info->getYData().second;
            for (double x : xData)
            {
                if (x >= *minMax.first && x <= *minMax.second)
                {
                    set.insert(x);
                }
            }
            auto keyData = QVector<double>::fromStdVector(std::vector(set.begin(), set.end()));
            QVector<double> valueData;
            double fac = isCheckBoxChecked ? incidentWaveFieldValue : 1.0;
            valueData.reserve(keyData.size());
            for (double key : keyData)
            {
                double value = caculateGraphValueByKey(key, graphData);
                for (int i = 1; i < xData.size(); ++i)
                {
                    double previous = xData.at(i - 1);
                    double next = xData.at(i);
                    if (key == previous)
                    {
                        value *= yData.at(i - 1) / fac;
                        break;
                    }
                    else if (key > previous && key <= next)
                    {
                        value *= yData.at(i) / fac;
                        break;
                    }
                }
                valueData.append(value);
            }


            QString params = QString::number(DataAnalysisType::HIRF) + ","
                + graphNameList.join(",") + ","
                + QString::number(incidentWaveFieldValue) + ","
                + typeName + ","
                + QFileInfo(textFileParser->GetFileName()).completeBaseName() + ","
                + QString::number(isCheckBoxChecked);

            if (!getIsEdit())
            {
                Info2DPointer HIRFInfo = Info2DPointer::create(*newInfo);
                HIRFInfo->getXDataPointer()->second = std::move(keyData);
                HIRFInfo->getYDataPointer()->second = std::move(valueData);

                QString _tempName{};
                if (typeName == "E_total")
                    _tempName = QStringLiteral("电场");
                else if (typeName == "I")
                    _tempName = QStringLiteral("电流");
                info->getYDataPointer()->first.replace(QRegularExpression("^.?(?=_)"), graphNameList.first() + "_" + _tempName);
                auto _environmentName = QFileInfo(textFileParser->GetFileName()).completeBaseName();
                _environmentName = _environmentName.mid(4);
                QString _IncidentWaveValue = "1V/m";
                if (isCheckBoxChecked)
                {
                    _IncidentWaveValue = QString::number(incidentWaveFieldValue) + "V/m";
                }
                auto name = info->getYDataPointer()->first + QStringLiteral("_%1外推").arg(_environmentName) + "_" + _IncidentWaveValue + "_" + QString::number(m_hirfExtrapolationId++);
                while (getHasSameName(name))
                {
                    name += "_1";
                }

                HIRFInfo->getYDataPointer()->first = name;
                HIRFInfo->setCurveName(name);
                HIRFInfo->getYDataPointer()->first = _tempName + QStringLiteral("外推");
                HIRFInfo->setIsNewData(true);
                HIRFInfo->setIsOnlyShow(true);
                HIRFInfo->setValueIndex(0);
                HIRFInfo->setGraph(this);
                HIRFInfo->setDataSources(QString());
                slot_removeGraphs({ HIRFInfo->getCurveName() });

                this->addNewGraph(HIRFInfo, params);
                m_addCurveInfo.append(HIRFInfo);
                //往tempIO写出外推曲线数据，如有同名文件，则覆盖
                hirfExtrapolationCurvesDataExport(typeName, name, HIRFInfo, i);
            }
            else
            {
                QStandardItem* item = nullptr;
                QString curveName;
                if (i == 0)
                {
                    item = item1;
                    newInfo = dataInfo1;
                    curveName = curveName1;
                }
                else
                {
                    item = item2;
                    newInfo = dataInfo2;
                    curveName = curveName2;
                }

                newInfo->getXDataPointer()->second = std::move(keyData);
                newInfo->getYDataPointer()->second = std::move(valueData);

                QString _tempName{};
                if (typeName == "E_total")
                    _tempName = QStringLiteral("电场");
                else if (typeName == "I")
                    _tempName = QStringLiteral("电流");
                info->getYDataPointer()->first.replace(QRegularExpression("^.?(?=_)"), graphNameList.first() + "_" + _tempName);
                auto _environmentName = QFileInfo(textFileParser->GetFileName()).completeBaseName();
                _environmentName = _environmentName.mid(4);

                QString _IncidentWaveValue = "1V/m";
                if (isCheckBoxChecked)
                {
                    _IncidentWaveValue = QString::number(incidentWaveFieldValue) + "V/m";
                }
                auto name = info->getYDataPointer()->first + QStringLiteral("_%1外推").arg(_environmentName) + "_" + _IncidentWaveValue + "_" + QString::number(m_hirfExtrapolationId++); // curveName.split("_", QString::SkipEmptyParts).back();

                newInfo->getYDataPointer()->first = name;
                newInfo->setCurveName(newInfo->getYDataPointer()->first);
                newInfo->getYDataPointer()->first = _tempName + QStringLiteral("外推");
                newInfo->setIsNewData(true);
                newInfo->setIsOnlyShow(true);
                newInfo->setValueIndex(0);
                updateCurve(item, newInfo);
                // 往tempIO写出外推曲线数据，覆盖原数据
                hirfExtrapolationCurvesDataExport(typeName, name, newInfo, i);
            }
        }

        // m_hirfExtrapolationId++;
        return true;
    }

    void LineChartWindow::hirfExtrapolationCurvesDataExport(const QString& typeName, const QString& newFileName, const Info2DPointer& info, int times)
    {
        QString keyName;
        QVector<double> keyData;
        Info2DPointer firstEffectiveinfo = Info2DPointer::create();
        QString unit = m_unit;
        unit.remove(QRegularExpression("\\[|]"));
        // 获取所有x数据值

        if (info->getCurveLineAddress() == nullptr)
        {
            return;
        }
        keyName = info->getXData().first + "||" + unit + "||key";
        keyData.append(info->getXData().second);

        std::set set(keyData.begin(), keyData.end()); // 保持数据顺序去重
        keyData = QVector<double>::fromStdVector(std::vector(set.begin(), set.end()));
        QVector<QPair<QString, QVector<double>>> datas; // 所有数据数组
        datas.append(qMakePair(keyName, keyData));      // 添加x数据

        auto graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        if (graph == nullptr)
        {
            return;
        }
        if (firstEffectiveinfo->getCurveLineAddress() == nullptr)
        {
            firstEffectiveinfo = info;
        }
        QSharedPointer<QCPGraphDataContainer> graphData(graph->data());
        QVector<double> valueData;
        valueData.reserve(keyData.size());
        for (double key : keyData)
        {
            double value = caculateGraphValueByKey(key, graphData);
            valueData.append(value);
        }
        QString valueName = info->getYData().first;

        if (typeName == "E_total")
            valueName.append("||V/m");
        else if (typeName == "I")
            valueName.append("||mA");
        valueName.append("||value");
        datas.append(qMakePair(valueName, std::move(valueData)));
        if (typeName == "E_total") // 点电场
        {
            if (times == 0) // 峰值
            {
                m_tempValueData.first = datas.at(1).first;
                m_tempValueData.second = datas.at(1).second;
            }
        }

        if (datas.size() == 1)
        {
            IBaseSignalInstance->signal_sendErrorMessageToUI("未找到曲线");
            return;
        }

        QString dirName = GlobalHelperInstance->getProjectTempIODir() + "/HirfExtrapolation";
        QDir _dir(dirName);
        if (!_dir.exists(dirName))
        {
            qDebug() << "Warning: HirfExtrapolation path does not exist";
            auto isOk = _dir.mkpath(dirName);
            isOk ? qDebug() << "HirfExtrapolation path creation succeeded!" : qDebug() << "Warning: HirfExtrapolation path creation failed!";
        }

        // 移除旧文件
        // 处理同一个项目树节点打开多个窗口进行hirf外推的情况，函数中内置判断
        WindowTotalDataInstance->removeHirfExtrapolationCurveDataByInfo(info);

        //生成新文件
        auto _newFileName = newFileName + ".txt";
        _newFileName.remove(QRegularExpression("V/m"));
        QString _fileName = dirName + "/" + _newFileName;
        if (writeHirfExtrapolationDataToFile(_fileName, datas))
            WindowTotalDataInstance->addHirfExtrapolationCurveData(info, newFileName);
        else
            IBaseSignalInstance->signal_sendErrorMessageToUI("HIRF外推曲线保存失败！");

        if (typeName == "E_total") // 点电场
        {
            if (times == 1)
            {
                datas.insert(1, m_tempValueData);
                auto _reader = info->getReader();
                auto _filePath = _reader->GetFileName();
                _newFileName = _filePath.split('/').last();
                _fileName = dirName + "/" + _newFileName;
                if (writeHirfExtrapolationDataToFile(_fileName, datas))
                {
                    WindowTotalDataInstance->addHirfExtrapolationCurveData(info, _newFileName, true);
                }
                else
                    IBaseSignalInstance->signal_sendErrorMessageToUI("HIRF外推曲线保存失败！");
            }
        }
    }

    bool LineChartWindow::writeHirfExtrapolationDataToFile(QString fileName, QVector<QPair<QString, QVector<double>>> datas)
    {
        QFile file(fileName);
        if (file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream out(&file);
            // 设置 QTextStream 的编码为 UTF-8
            out.setCodec("UTF-8");
            // 可选：写入 BOM，如果需要 Excel 正确识别 UTF-8 BOM
            file.write("\xEF\xBB\xBF");

            out << "# comac datafile version 1.0" << "\n";

            QStringList dataName;
            for (auto iter = datas.begin(); iter != datas.end(); ++iter)
            {
                dataName.append(iter->first);
            }
            out << "# " + dataName.join(" , ") << "\n";

            int num = datas.first().second.size();
            for (int i = 0; i < num; ++i)
            {
                QStringList dataValue;
                for (int j = 0; j < datas.size(); ++j)
                {
                    const auto& data = datas.at(j);
                    int significantBit = 5;
                    if (j > 0)
                    {
                        significantBit = 8;
                    }
                    dataValue.append(QString::number(data.second.at(i), 'E', significantBit));
                }
                out << dataValue.join(" , ") << "\n";
            }
            file.close();
        }
        else
            return false;
        return true;
    }

    void LineChartWindow::slot_computeEffectiveness(const QStringList& graphNameList, double e0)
    {
        if (e0 <= 0)
        {
            return;
        }
        QVector<CalculationData> powerVector;
        auto dataList = GetCurveDataByNames(graphNameList);
        for (const auto& data : dataList)
        {
            if (data.first.isEmpty())
            {
                continue;
            }
            CalculationData tmp;
            if (Power({ data, CalculationData({2}, {}) }, tmp))
            {
                powerVector.append(std::move(tmp));
            }
            else
            {
                return;
            }
        }
        CalculationData sum;
        if (powerVector.size() == 1)
        {
            sum = powerVector.first();
        }
        else if (!Add(powerVector, sum))
        {
            return;
        }
        CalculationData total;
        if (!Sqrt({ sum }, total))
        {
            return;
        }
        CalculationData divide;
        if (!Divide({ total, CalculationData({e0}, {}) }, divide))
        {
            return;
        }
        CalculationData lg;
        if (!Log({ divide }, lg))
        {
            return;
        }
        CalculationData result;
        if (!Multiply({ lg, CalculationData({-20}, {}) }, result))
        {
            return;
        }
        if (result.second.isEmpty() || result.first.size() != result.second.size())
        {
            return;
        }

        if (!getIsEdit())
        {
            auto info = Info2DPointer::create(*m_curveMap.at(0).second);
            auto yDataPointer = info->getYDataPointer();
            yDataPointer->second = result.first;
            info->getXDataPointer()->second = result.second;
            yDataPointer->first = "屏蔽效能";
            QString name = "屏蔽效能_" + QString::number(m_effectivenessNumber++);
            while (getHasSameName(name))
            {
                name += "_1";
            }

            info->setCurveName(name);
            info->setIsNewData(true);
            info->setIsOnlyShow(true);
            info->setValueIndex(0);
            info->setGraph(this);
            info->setDataSources(QString());
            QString params = QString::number(DataAnalysisType::Effectiveness) + "," + graphNameList.join(',') + "," + QString::number(e0);
            this->addNewGraph(info, params);
            m_addCurveInfo.append(info);
        }
        else
        {
            for (auto& curvePair : m_curveMap)
            {
                auto item = curvePair.first;
                auto& info = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
                if (graph->selected())
                {
                    QString newParams = QString::number(DataAnalysisType::Effectiveness) + "," + graphNameList.join(",") + "," + QString::number(e0);
                    item->setData(newParams, Qt::UserRole + 3);

                    auto yDataPointer = info->getYDataPointer();
                    yDataPointer->second = result.first;
                    info->getXDataPointer()->second = result.second;
                    info->setIsNewData(true);
                    info->setIsOnlyShow(true);
                    info->setValueIndex(0);
                    updateCurve(item, info);
                    break;
                }
            }
        }
    }

    void LineChartWindow::slot_computeTransferFunction(const QString& graphName, const QString& calibrationGraphName, const QString& type)
    {
        QStandardItem* item = nullptr;
        Info2DPointer dataInfo = nullptr;
        QString curveName;
        if (!getIsEdit())
        {
            dataInfo = Info2DPointer::create();
            for (auto curvePair : m_curveMap)
            {
                auto& infoTmp = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(infoTmp->getCurveLineAddress());
                if (graphName == graph->name())
                {
                    if (dataInfo->getCurveLineAddress() == nullptr)
                    {
                        dataInfo = Info2DPointer::create(*infoTmp);
                        break;
                    }
                }
            }
        }
        else
        {
            for (auto& curvePair : m_curveMap)
            {
                item = curvePair.first;
                dataInfo = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(dataInfo->getCurveLineAddress());
                if (graph->selected())
                {
                    curveName = graph->name();
                    break;
                }
            }

            QString params = QString::number(DataAnalysisType::TransferFunction) + "," + graphName + "," + calibrationGraphName + "," + type;
            item->setData(params, Qt::UserRole + 3);
        }

        if (dataInfo->getCurveLineAddress() == nullptr)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("未找到计算曲线！"), EDialogMsg::Error, QStringLiteral("传递函数计算错误"));
            return;
        }
        auto dataList = GetCurveDataByNames({ graphName, calibrationGraphName });
        if (dataList.size() != 2)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("未找到相关曲线！"), EDialogMsg::Error, QStringLiteral("传递函数计算错误"));
            return;
        }
        const auto& computeData = dataList.first();
        const auto& calibratioData = dataList.last();
        if (computeData.first.isEmpty() || calibratioData.first.isEmpty())
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("未找到相关曲线！"), EDialogMsg::Error, QStringLiteral("传递函数计算错误"));
            return;
        }
        auto computeMinMax = std::minmax_element(computeData.second.begin(), computeData.second.end());
        auto calibratioMinMax = std::minmax_element(calibratioData.second.begin(), calibratioData.second.end());
        double min = *computeMinMax.first > *calibratioMinMax.first ? *computeMinMax.first : *calibratioMinMax.first;
        double max = *computeMinMax.second < *calibratioMinMax.second ? *computeMinMax.second : *calibratioMinMax.second;
        if (min > max)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("没有交集！"), EDialogMsg::Error, QStringLiteral("传递函数计算错误"));
            return;
        }
        QCPRange range(min, max);
        CalculationData divide;
        if (!Divide({ computeData, calibratioData }, divide))
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("曲线相除错误！"), EDialogMsg::Error, QStringLiteral("传递函数计算错误"));
            return;
        }
        CalculationData result;
        for (int i = 0; i < divide.second.size(); ++i)
        {
            double n = divide.second.at(i);
            if (range.contains(n))
            {
                result.first.append(divide.first.at(i));
                result.second.append(divide.second.at(i));
            }
        }

        if (!getIsEdit())
        {
            auto yDataPointer = dataInfo->getYDataPointer();
            yDataPointer->first = "传递函数";
            yDataPointer->second = result.first;
            dataInfo->getXDataPointer()->second = result.second;

            auto name = QString("%1_%2_%3传递函数曲线").arg(graphName).arg(calibrationGraphName).arg(type) + "_" + QString::number(m_computeTransferId++);
            while (getHasSameName(name))
            {
                name += "_1";
            }

            dataInfo->setCurveName(name);
            dataInfo->setIsNewData(true);
            dataInfo->setIsOnlyShow(true);
            dataInfo->setValueIndex(0);
            dataInfo->setGraph(this);
            dataInfo->setDataSources(QString());
            QString params = QString::number(DataAnalysisType::TransferFunction) + "," + graphName + "," + calibrationGraphName + "," + type;
            this->addNewGraph(dataInfo, params);
            m_addCurveInfo.append(dataInfo);
        }
        else
        {
            auto yDataPointer = dataInfo->getYDataPointer();
            yDataPointer->first = "传递函数";
            yDataPointer->second = result.first;
            dataInfo->getXDataPointer()->second = result.second;

            QString No = curveName.split("_", QString::SkipEmptyParts).back();
            auto name = QString("%1_%2_%3传递函数曲线").arg(graphName).arg(calibrationGraphName).arg(type) + "_" + No;

            dataInfo->setCurveName(name);
            dataInfo->setIsNewData(true);
            dataInfo->setIsOnlyShow(true);
            dataInfo->setValueIndex(0);
            updateCurve(item, dataInfo);
        }
    }

    static bool GetPublicScope(const QList<CalculationData>& graphDataList, QCPRange& range)
    {
        double min = DBL_MIN;
        double max = DBL_MAX;
        for (const auto& graphData : graphDataList)
        {
            auto minMax = std::minmax_element(graphData.second.begin(), graphData.second.end());
            min = *minMax.first > min ? *minMax.first : min;
            max = *minMax.second < max ? *minMax.second : max;
        }
        if (min > max)
        {
            return false;
        }
        range = { min, max };
        return true;
    }

    void LineChartWindow::slot_computeIPL(const QList<QVariant>& IPLDatas,bool* success)
    {
        QStandardItem* item = nullptr;
        Info2DPointer dataInfo = nullptr;
        if (!getIsEdit())
        {
            dataInfo = Info2DPointer::create();
            if (!m_curveMap.isEmpty())
            {
                dataInfo = Info2DPointer::create(*m_curveMap.at(0).second);
            }
            if (dataInfo->getCurveLineAddress() == nullptr)
            {
                auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("没有任何曲线！"), EDialogMsg::Error, QStringLiteral("传递函数计算错误"));
                *success = false;
                return;
            }
        }
        else
        {
            for (auto& curvePair : m_curveMap)
            {
                item = curvePair.first;
                dataInfo = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(dataInfo->getCurveLineAddress());
                if (graph->selected())
                {
                    break;
                }
            }

            QStringList stringList;
            for (const QVariant& variant : IPLDatas)
            {
                stringList << variant.toString();
            }
            QString params = QString::number(DataAnalysisType::IPL) + "," + stringList.join(",");
            item->setData(params, Qt::UserRole + 3);
        }

        QList<QString> names;
        QList<CalculationData> allDatas;
        for (const auto& var : IPLDatas)
        {
            if (var.type() == QVariant::String)
            {
                names.append(var.toString());
            }
        }
        auto graphDataList = GetCurveDataByNames(names);
        int graphDataIndex = 0;
        for (const auto& var : IPLDatas)
        {
            if (var.type() == QVariant::Double)
            {
                allDatas.append(CalculationData({ var.toDouble() }, {}));
            }
            else if (var.type() == QVariant::String)
            {
                if (graphDataIndex < graphDataList.size())
                {
                    allDatas.append(graphDataList.at(graphDataIndex++));
                }
                else
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("未找到计算曲线！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
                    *success = false;
                    return;
                }
            }
        }
        if (allDatas.size() != 7)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("数据个数错误！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
            *success = false;
            return;
        }
        CalculationData tC_Subtract_mC;
        if (!Subtract({ allDatas.at(2), allDatas.at(3) }, tC_Subtract_mC))
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("TC Subtract MC错误！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
            *success = false;
            return;
        }
        CalculationData subtract_1;
        if (!Subtract({ allDatas.at(0), allDatas.at(1), tC_Subtract_mC }, subtract_1))
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("前半段相减错误！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
            *success = false;
            return;
        }
        CalculationData add;
        if (!Add({ subtract_1, allDatas.at(4), allDatas.at(5) }, add))
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("相加错误！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
            *success = false;
            return;
        }
        CalculationData subtract_2;
        if (!Subtract({ add, allDatas.at(6) }, subtract_2))
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("减去ATT错误！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
            *success = false;
            return;
        }
        CalculationData result;
        if (graphDataList.isEmpty())
        {
            if (subtract_2.first.size() != 1)
            {
                auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("无曲线的IPL计算错误！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
                *success = false;
                return;
            }
            result.first = { subtract_2.first.first(), subtract_2.first.first() };
            result.second = { m_customPlot->xAxis->range().lower, m_customPlot->xAxis->range().upper };
        }
        else
        {
            QCPRange range;
            if (!GetPublicScope(graphDataList, range))
            {
                auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("选择的多条曲线无交集范围，请重新选择曲线！"), EDialogMsg::Error, QStringLiteral("IPL计算错误"));
                *success = false;
                return;
            }
            for (int i = 0; i < subtract_2.second.size(); ++i)
            {
                double n = subtract_2.second.at(i);
                if (range.contains(n))
                {
                    result.first.append(subtract_2.first.at(i));
                    result.second.append(subtract_2.second.at(i));
                }
            }
        }

        if (!getIsEdit())
        {
            auto yDataPointer = dataInfo->getYDataPointer();
            yDataPointer->first = "IPL生成曲线";
            yDataPointer->second = result.first;
            dataInfo->getXDataPointer()->second = result.second;

            QString name = "IPL生成曲线_" + QString::number(m_IPLId++);
            while (getHasSameName(name))
            {
                name += "_1";
            }
            dataInfo->setCurveName(name);
            dataInfo->setIsNewData(true);
            dataInfo->setIsOnlyShow(true);
            dataInfo->setValueIndex(0);
            dataInfo->setGraph(this);
            dataInfo->setDataSources(QString());
            QStringList stringList;
            for (const QVariant& variant : IPLDatas)
            {
                stringList << variant.toString();
            }
            QString params = QString::number(DataAnalysisType::IPL) + "," + stringList.join(",");
            this->addNewGraph(dataInfo, params);
            m_addCurveInfo.append(dataInfo);
        }
        else
        {
            auto yDataPointer = dataInfo->getYDataPointer();
            yDataPointer->first = "IPL生成曲线";
            yDataPointer->second = result.first;
            dataInfo->getXDataPointer()->second = result.second;

            dataInfo->setIsNewData(true);
            dataInfo->setIsOnlyShow(true);
            dataInfo->setValueIndex(0);
            updateCurve(item, dataInfo);
        }
    }

    // 二阶节结构：分子系数 b0,b1,b2；分母系数 a1,a2；内部状态 w1,w2
    struct Sos
    {
        double b0, b1, b2;
        double a1, a2;
        double w1 = 0, w2 = 0;
    };

    // 预扭频率：将数字截止频率映射到模拟域
    static double prewarp(double fc, double fs)
    {
        return std::tan(M_PI * fc / fs);
    }

    bool LineChartWindow::slot_computeWaveformAnalysis(const QString& graphName, double cutOffFrequency, const QString& filterType, int filterOrder, double leftBoundary, double rightBoundary, int windowId, QString resultList, bool isPythonRun)
    {
        QStandardItem* item = nullptr;
        Info2DPointer dataInfo = Info2DPointer::create();
        m_waveParams = QString("%1,%2,%3,%4,%5,%6,%7")
            .arg(DataAnalysisType::WaveformAnalysis)
            .arg(graphName)
            .arg(cutOffFrequency)
            .arg(filterType)
            .arg(filterOrder)
            .arg(leftBoundary)
            .arg(rightBoundary);

        if (!getIsEdit())
        {
            for (auto curvePair : m_curveMap)
            {
                auto& infoTmp = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(infoTmp->getCurveLineAddress());
                if (graphName == graph->name())
                {
                    if (dataInfo->getCurveLineAddress() == nullptr)
                    {
                        dataInfo = Info2DPointer::create(*infoTmp);
                        break;
                    }
                }
            }
        }
        else
        {
            for (auto& curvePair : m_curveMap)
            {
                item = curvePair.first;
                dataInfo = curvePair.second;
                QCPGraph* graph = qobject_cast<QCPGraph*>(dataInfo->getCurveLineAddress());
                if (graph->selected())
                {
                    break;
                }
            }
            QString params = /*QString::number(DataAnalysisType::WaveformAnalysis) + "," + */m_waveParams;
            item->setData(params, Qt::UserRole + 3);
            m_waveItem = item;
        }
        if (dataInfo->getCurveLineAddress() == nullptr)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("未找到曲线！"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
            return false;
        }

        // x轴只能是时间轴
        if (m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_xUnitType != 1)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("该功能仅支持时域数据曲线，请重新选择时域数据曲线。"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
            return false;
        }

        // 单位转换因子
        double convertNumber = 1.0;
        if (m_unit == "[ms]")
        {
            convertNumber = 1E3;
        }
        else if (m_unit == "[us]")
        {
            convertNumber = 1E6;
        }
        else if (m_unit == "[ns]")
        {
            convertNumber = 1E9;
        }
        else if (m_unit == "[ps]")
        {
            convertNumber = 1E12;
        }
        else if (m_unit == "[s]")
        {
            convertNumber = 1.0;
        }
        else if (m_unit == "[min]")
        {
            convertNumber = 1 / 60.0;
        }
        else if (m_unit == "[h]")
        {
            convertNumber = 1 / 3600.0;
        }


        QVector<double> keyData, valueData;
        for (int i = 0; i < m_customPlot->graphCount(); ++i)
        {
            auto graph = m_customPlot->graph(i);
            if (graphName.compare(graph->name(), Qt::CaseInsensitive) == 0)
            {
                const auto& graphData = graph->data();

                bool hasRange = false;
                auto graphRange = graphData->keyRange(hasRange);
                if (!hasRange)
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("曲线无数据！"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                    return false;
                }

                // 输入采样率检查
                if (graphData->size() < 2)
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("曲线数据过少！"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                    return false;
                }
                {
                    double sampleRate = 1.0 / ((graphData->at(1)->key - graphData->at(0)->key) / convertNumber); // 以s为单位
                    double maxCutOffFrequency = sampleRate / 2.0 / 1000000.0;                                    // 以MHz为单位
                    if (0.0 > cutOffFrequency || cutOffFrequency > maxCutOffFrequency)
                    {
                        auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("截止频率需在0~") + QString::number(maxCutOffFrequency) + QStringLiteral("MHz范围内"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                        return false;
                    }
                }

                // 阶数判断
                if (filterOrder % 2 != 0)
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("仅支持正偶数阶"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                    return false;
                }

                QCPRange range;
                if (std::isnan(leftBoundary))
                {
                    range.lower = graphRange.lower;
                    range.lower /= convertNumber; // 转换成s
                }
                else
                {
                    range.lower = leftBoundary;
                    range.lower /= 1E6; // 转换成s
                }

                if (range.lower < graphRange.lower / convertNumber || range.lower > graphRange.upper / convertNumber) // 统一转成s后比较
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("时域定义左边超出曲线范围！"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                    return false;
                }


                if (std::isnan(rightBoundary))
                {
                    range.upper = graphRange.upper;
                    range.upper /= convertNumber; // 转换成s
                }
                else
                {
                    range.upper = rightBoundary;
                    range.upper /= 1E6; // 转换成s
                }
                if (range.upper > graphRange.upper / convertNumber || range.upper < graphRange.lower / convertNumber) // 统一转成s后比较
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("时域定义右边超出曲线范围！"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                    return false;
                }

                if (range.lower > range.upper)
                {
                    auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("时域定义左边需小于等于时域定义右边数据，请重新输入"), EDialogMsg::Error, QStringLiteral("波形分析计算错误"));
                    return false;
                }

                for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
                {
                    double key = iter->key;

                    key /= convertNumber; // 转成s
                    if (range.contains(key))
                    {
                        keyData.append(key);
                        valueData.append(iter->value);
                    }
                }
                if (!keyData.contains(range.lower))
                {
                    keyData.insert(0, range.lower);
                    valueData.insert(0, caculateGraphValueByKey(range.lower * convertNumber, graphData)); // 转换为曲线当前单位
                }
                if (!keyData.contains(range.upper))
                {
                    keyData.append(range.upper);
                    valueData.append(caculateGraphValueByKey(range.upper * convertNumber, graphData));
                }
                break;
            }

        }
        double cutoffFreq = cutOffFrequency * 1E6; // 转成Hz
        int filtOrder = filterOrder / 2;
        double sampleRate = 1.0 / (keyData.at(1) - keyData.at(0)); // 除数以s为单位

        for (auto& k : keyData) // 转回当前单位m_unit
        {
            k *= convertNumber;
        }

        QString valueListStr = GlobalHelperInstance->convertDoubleListToQString(valueData.toList());
        // m_currentUsingWaveButterAndFFTInfo = Info2DPointer::create();
        m_currentUsingWaveButterAndFFTInfo = dataInfo;
        m_currentUsingWaveButterAndFFTInfo->getXDataPointer()->second = keyData;

        if (!isPythonRun)
        {
            QStringList _pyCode;
            _pyCode.append(QString("PostProcessing.doWaveButterANdFFTV(%1,'%2',%3,%4,'%5',%6, %7)").arg(cutoffFreq).arg(filterType).arg(filtOrder).arg(sampleRate).arg(valueListStr).arg(m_windowId).arg(isPythonRun));
            emit IBaseSignalInstance->signal_execPYCode(_pyCode, false, true);

            QString _pyCode1 = QString("PostProcessing.lineChartDialogWaveformAnalysis('%1',%2,'%3',%4,'%5','%6',%7,'%8',%9,%10,'%11',%12)")
                                  .arg(graphName)
                                  .arg(cutOffFrequency)
                                  .arg(filterType)
                                  .arg(filterOrder)
                                  .arg(std::isnan(leftBoundary) ? QString("nan") : QString::number(leftBoundary))
                                  .arg(std::isnan(rightBoundary) ? QString("nan") : QString::number(rightBoundary))
                                  .arg(cutoffFreq)
                                  .arg(filterType)
                                  .arg(filtOrder)
                                  .arg(sampleRate)
                                  .arg(valueListStr)
                                  .arg(m_windowId);
            emit IBaseSignalInstance->signal_execPYCode(QStringList{_pyCode1}, true, false);
        }
        else
        {
            if (!resultList.isEmpty())
            {
                QList<double> resultList1 = GlobalHelperInstance->convertStringToDoubleList(resultList);
                pyShowWaveButterAndFFT(resultList1);
            }
        }

        // QVector<Sos> sosSeries;
        // designButterSOS(filtOrder, cutoffFreq, sampleRate, filterType == "low" ? false : true, sosSeries);
        // sosfiltfilt(sosSeries, valueData);
        // auto yDataPointer = dataInfo->getYDataPointer();
        // yDataPointer->first = "波形分析";
        // yDataPointer->second = valueData;
        // dataInfo->getXDataPointer()->second = keyData;
        // dataInfo->setCurveName(dataInfo->getCurveName().remove(QRegularExpression("\\[.*?]$")) + "_波形分析");
        // dataInfo->setIsNewData(true);
        // dataInfo->setIsOnlyShow(true);
        // dataInfo->setValueIndex(0);
        // dataInfo->setGraph(this);
        // dataInfo->setDataSources(QString());
        // this->addNewGraph(dataInfo);
    }

    void LineChartWindow::pyShowWaveButterAndFFT(const QList<double>& yData)
    { // QVector<Sos> sosSeries;
        auto yDataPointer = m_currentUsingWaveButterAndFFTInfo->getYDataPointer();
        yDataPointer->first = "波形分析结果";
        yDataPointer->second = yData.toVector();
        // m_currentUsingWaveButterAndFFTInfo->getXDataPointer()->second = keyData;

        if (!getIsEdit())
        {
            QString curveName = m_currentUsingWaveButterAndFFTInfo->getCurveName() /*.remove(QRegularExpression("\\[.*?]$")) */ + "_波形分析" + "_" + QString::number(m_waveAnalysisId++);
            while (getHasSameName(curveName))
            {
                curveName += "_1";
            }

            m_currentUsingWaveButterAndFFTInfo->setCurveName(curveName);
            m_currentUsingWaveButterAndFFTInfo->setGraph(this);
            m_currentUsingWaveButterAndFFTInfo->setIsNewData(true);
            m_currentUsingWaveButterAndFFTInfo->setIsOnlyShow(true);
            m_currentUsingWaveButterAndFFTInfo->setValueIndex(0);
            m_currentUsingWaveButterAndFFTInfo->setDataSources(QString());

            this->addNewGraph(m_currentUsingWaveButterAndFFTInfo, m_waveParams);
            m_addCurveInfo.append(m_currentUsingWaveButterAndFFTInfo);
        }
        else
        {
            QString curveName = m_currentUsingWaveButterAndFFTInfo->getCurveName() /*.remove(QRegularExpression("\\[.*?]$")) */ + "_波形分析" + "_" + QString::number(m_waveAnalysisId++);
            while (getHasSameName(curveName))
            {
                curveName += "_1";
            }

            m_currentUsingWaveButterAndFFTInfo->setCurveName(curveName);
            m_currentUsingWaveButterAndFFTInfo->setIsNewData(true);
            m_currentUsingWaveButterAndFFTInfo->setIsOnlyShow(true);
            m_currentUsingWaveButterAndFFTInfo->setValueIndex(0);

            updateCurve(m_waveItem, m_currentUsingWaveButterAndFFTInfo);
        }
    }

    void LineChartWindow::pyAddTracer( QString parameters)
    {
        auto tracer = new LineChartTracer(m_customPlot);
        importTracerFromList(parameters, m_customPlot, tracer);
        auto tracerPropertyWidget = m_tracerPropertyWidget;
        if (tracerPropertyWidget->isHidden())
        {
            QPoint p(0, 0);
            if (!m_measureTableWidget->isHidden() && m_measureTableWidget->geometry().x() < m_customPlot->axisRect()->topLeft().x() + 20)
            {
                p.setX(m_measureTableWidget->width() + 10);
            }
            tracerPropertyWidget->move(m_customPlot->axisRect()->topLeft() + p + QPoint(10, 10));
            tracerPropertyWidget->show();
        }
        tracerPropertyWidget->AppendTracerProperty(tracer);

        auto tmp = tracer->getStyle2DTracerProperty();
        tmp->m_tracerName = tracer->GetName();
        tmp->m_x = tracer->position->coords().x();
        tmp->m_symbolStyle = tracer->style() - 1;
        tmp->m_symbolSize = tracer->size() / 2;
        tmp->m_symbolColor = tracer->pen().color();
        // previewTracer->setVisible(false);
        // m_customPlot->SetIsShowPreviewTracer(false);
        m_customPlot->replot();
    }

    void LineChartWindow::slot_getSidebarCurveDataSource(QString& dataSource)
    {
        Info2DPointer info = Info2DPointer::create();
        for (const auto& infoTmpPair : m_curveMap)
        {
            if (infoTmpPair.second->getCurveName() == dataSource)
            {
                info = infoTmpPair.second;
                dataSource = info->getDataSources();
                break;
            }
        }
    }

    void LineChartWindow::slot_autoGetXTitleText(QString& xTitleText)
    {
        if (m_curveMap.isEmpty())
        {
            return;
        }
        const auto& info = m_curveMap.at(0).second;
        QString unit = info->getReader()->getEachColUnitOfKey().at(info->getReader()->getScanParameterIndex()).trimmed();
        if (unit == "MHz")
        {
            // xTitleText = "Frequency";
            xTitleText = QStringLiteral("频率");
            ;
        }
        else if (unit == "us")
        {
            // xTitleText = "Time";
            xTitleText = QStringLiteral("时间");
        }
        else
        {
            xTitleText = info->getReader()->getEachColNameOfKey().at(info->getReader()->getScanParameterIndex()).trimmed();
        }
    }

    void LineChartWindow::slot_autoGetYTitleText(QString& yTitleText)
    {
        QStringList nameList;
        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        auto selectionModel = m_settings->getCurveNameListView()->selectionModel();
        for (auto row = 0; row < model->rowCount(); row++)
        {
            QStandardItem* item = model->item(row);

            const auto& info = getCurveInfoByItem(item);
            auto graph = info->getCurveLineAddress();
            if (graph == nullptr || !graph->visible())
            {
                continue;
            }
            QString name;
            auto reder = info->getReader();
            int index = reder->getRealValueIndex(info->getValueIndex(), info->getValueComponent());

            if (index < 0 || index >= reder->getEachColUnitOfValue().size())
            {
                index = 0;
            }

            auto table = reder->getOriginalTable();

            auto array = table->GetColumn(index + reder->getEachColNameOfKey().size());
            TextArrayMetaStruct struct1;
            TextArrayMetaHander::getArrayMeta(array, struct1);
            switch (struct1.resultParaType)
            {
            case 0:
            case 1:
                name = "电场";
                break;
            case 7:
                name = "增益";
                break;
            case 8:
                name = "S参数";
                break;
            case 9:
                name = "驻波比";
                break;
            case 10:
                name = "电压";
                break;
            case 11:
                name = "电流";
                break;
            case 13:
                name = "人体吸收比";
                break;
            case 16:
                name = "功率";
                break;
            case 17:
                name = "方向性系数";
                break;
            case 18:
                name = "雷达散射截面";
                break;
            case 19:
                name = "反射系数";
                break;
            case 20:
                name = "磁场";
                break;
            default:
                break;
            }
            if (!name.isEmpty())
            {
                if (!nameList.contains(name))
                {
                    nameList.append(name);
                }
            }
        }
        yTitleText = nameList.join(",");
    }

    void LineChartWindow::slot_changeAllCurveVariableAxis(const QString& newVariableAxisName)
    {

        for (auto dataInfo : m_curveMap)
        {
            // 对所有选择的数据单独处理
            auto _graph = dataInfo.second->getGraph();
            auto _reader = dataInfo.second->getReader();
            auto* curveAdd = dataInfo.second->getCurveLineAddress();

            if (curveAdd == nullptr || _graph == nullptr || _reader == nullptr)
            {
                // TODO 警告
                return;
            }

            // auto changedScanName = changedInfo.getScanParameterName();
            auto keyNames = _reader->getEachColNameOfKey();
            int newScanIndex = keyNames.indexOf(newVariableAxisName);
            // 设置新的扫描参数
            if (newScanIndex == -1)
            {
                // TODO 警告
                continue;
            }

            auto oldScanIndex = dataInfo.second->getScanParameterIndex();
            auto keyDataList = _reader->getEachColDataOfKey();
            dataInfo.second->setScanParameterIndex(newScanIndex);
            _reader->setScanParameterIndex(newScanIndex);

            // 设置新的otherKeyList
            QVector<double> otherKeyVector = dataInfo.second->getOtherKeyData();
            otherKeyVector.insert(oldScanIndex, keyDataList[oldScanIndex][0]);
            otherKeyVector.removeAt(newScanIndex);
            QVector<QVector<double>> tempOtherKey;
            for (auto i : otherKeyVector)
            {
                tempOtherKey.append(QVector<double>{i});
            }
            _reader->setOtherKeyParameter(tempOtherKey);
            dataInfo.second->setOtherKeyData(otherKeyVector);

            QPair<int, int> tem{ dataInfo.second->getValueIndex(), dataInfo.second->getValueComponent() };
            QList<Info2DPointer> newYList;
            _reader->getChosenLinesFromKey(QList<QPair<int, int>>{tem}, newYList);

            updateCurve(dataInfo.first, dataInfo.second);
        }
        QList<QStandardItem*> items;
        for (auto curvePair : m_curveMap)
        {
            items.append(curvePair.first);
        }
        slot_chosenItemsChanged(items);
    }

    void LineChartWindow::slot_submitEvaluation(int emulationType, const QStringList& graphNameList)
    {
        submitEvaluation(emulationType, graphNameList, true);
    }

    void LineChartWindow::pySubmitEvaluation(int emulationType, QString parms)
    {
        QHash<int, QStringList> map = GlobalHelperInstance->base64ToHash(parms);
        QStringList graphNameList = map[0];
        submitEvaluation(emulationType, graphNameList, false);
    }

    void LineChartWindow::submitEvaluation(int emulationType, const QStringList& graphNameList, bool savePy)
    {
        if (emulationType < 1 || emulationType > 4 || graphNameList.isEmpty())
        {
            IBaseSignalInstance->signal_sendErrorMessageToUI("没有选择提交曲线");
            return;
        }

        QList<Info2DPointer> infoList;
        for (const auto& graphName : graphNameList)
        {
            Info2DPointer info = Info2DPointer::create();
            for (const auto& infoTmp : m_curveMap)
            {
                if (infoTmp.second->getCurveName() == graphName)
                {
                    info = infoTmp.second;
                    break;
                }
            }
            infoList.append(info);
        }

        QString keyName;
        QVector<double> keyData;
        Info2DPointer firstEffectiveinfo = Info2DPointer::create();
        QString unit = m_unit;
        unit.remove(QRegularExpression("\\[|]"));
        // 获取所有x数据值
        for (const auto& info : infoList)
        {
            if (info->getCurveLineAddress() == nullptr)
            {
                continue;
            }
            keyName = info->getXData().first + "||" + unit + "||key";
            keyData.append(info->getXData().second);
        }
        std::set set(keyData.begin(), keyData.end()); // 保持数据顺序去重
        keyData = QVector<double>::fromStdVector(std::vector(set.begin(), set.end()));
        QVector<QPair<QString, QVector<double>>> datas; // 所有数据数组
        datas.append(qMakePair(keyName, keyData));      // 添加x数据

        for (int i = 0; i < infoList.size(); ++i)
        {
            const auto& info = infoList.at(i);
            auto graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            if (graph == nullptr)
            {
                continue;
            }
            if (firstEffectiveinfo->getCurveLineAddress() == nullptr)
            {
                firstEffectiveinfo = info;
            }
            QSharedPointer<QCPGraphDataContainer> graphData(graph->data());
            QVector<double> valueData;
            valueData.reserve(keyData.size());
            for (double key : keyData)
            {
                double value = caculateGraphValueByKey(key, graphData);
                valueData.append(value);
            }
            QString valueName = info->getYData().first;
            if (i == 0)
            {
                valueName.append("||V/m");
            }
            else if (i == 1)
            {
                if (emulationType == 2)
                {
                    valueName.append("||V/m");
                }
                else
                {
                    valueName.append("||mA");
                }
            }
            else
            {
                valueName.append("||mA");
            }
            valueName.append("||value");
            datas.append(qMakePair(valueName, std::move(valueData)));
        }
        if (datas.size() == 1)
        {
            IBaseSignalInstance->signal_sendErrorMessageToUI("未找到提交曲线");
            return;
        }

        QString dirName = g_outputDir;
        if (emulationType == 1)
        {
            dirName.append("/Lightning/");
        }
        else if (emulationType == 2)
        {
            dirName.append("/HIRF/");
        }
        else if (emulationType == 3)
        {
            dirName.append("/HPM/");
        }
        else if (emulationType == 4)
        {
            dirName.append("/HEMP/");
        }
        QDir _dir(dirName);
        if (!_dir.exists(dirName))
        {
            qDebug() << "Warning: Output path does not exist";
            auto isOk = _dir.mkpath(dirName);
            isOk ? qDebug() << "Output path creation succeeded!" : qDebug() << "Warning: Output path creation failed!";
        }
        ResultDataPointer resultDataPointer;
        emit signal_getTwoDResultDataPointer(firstEffectiveinfo->getReader(), resultDataPointer);
        QString pathName;
        if (!resultDataPointer.isNull())
        {
            if (!resultDataPointer->mulitFileInfo.second.isEmpty())
            {
                pathName = QFileInfo(resultDataPointer->path).dir().dirName() + "_";
            }
        }
        QFileInfo fileInfo(firstEffectiveinfo->getReader()->GetFileName());
        QString fileName = dirName + pathName + fileInfo.fileName();
        QFile file(fileName);
        if (file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QTextStream out(&file);
            // 设置 QTextStream 的编码为 UTF-8
            out.setCodec("UTF-8");
            // 可选：写入 BOM，如果需要 Excel 正确识别 UTF-8 BOM
            file.write("\xEF\xBB\xBF");

            out << "# comac datafile version 1.0" << "\n";

            QStringList dataName;
            for (auto iter = datas.begin(); iter != datas.end(); ++iter)
            {
                dataName.append(iter->first);
            }
            out << "# " + dataName.join(" , ") << "\n";

            int num = datas.first().second.size();
            for (int i = 0; i < num; ++i)
            {
                QStringList dataValue;
                for (int j = 0; j < datas.size(); ++j)
                {
                    const auto& data = datas.at(j);
                    int significantBit = 5;
                    if (j > 0)
                    {
                        significantBit = 8;
                    }
                    dataValue.append(QString::number(data.second.at(i), 'E', significantBit));
                }
                out << dataValue.join(" , ") << "\n";
            }
            file.close();
            if (savePy)
            {
                auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("评估提交成功！"), EDialogMsg::Normal, QStringLiteral("成功"), {QStringLiteral("确定")});
                QHash<int, QStringList> map;
                map.insert(0, graphNameList);
                QString args = "\"" + GlobalHelperInstance->hashToBase64(map) + "\"";
                QStringList _pyCodes{};
                _pyCodes += QString("appPrj = PostProcessing.AppPrj()");
                _pyCodes += QString("appPrj.submitEvaluation(%1,%2,%3)").arg(m_windowId).arg(emulationType).arg(args);
                emit IBaseSignalInstance->signal_execPYCode(_pyCodes, true, false);
            }
        }
        else
            IBaseSignalInstance->signal_sendErrorMessageToUI("导出文件打开失败，评估提交失败");
    }


    void LineChartWindow::slot_updateName()
    {
        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        for (auto row = 0; row < model->rowCount(); row++)
        {
            QStandardItem* item = model->item(row);
            if (!item->data().isNull() && item->data().toBool())
            {
                continue;
            }

            auto& info = getCurveInfoByItem(item);
            if (info->getIsNewData())
            {
                continue;
            }
            auto reader = info->getReader();
            int index = reader->getRealValueIndex(info->getValueIndex(), info->getValueComponent());
            auto table = reader->getOriginalTable();
            if (index < 0 || index >= reader->getEachColUnitOfValue().size())
            {
                index = 0;
            }
            auto array = table->GetColumn(index + reader->getEachColNameOfKey().size());
            TextArrayMetaStruct metaStruct;
            TextArrayMetaHander::getArrayMeta(array, metaStruct);
            QString valueStr;
            if (metaStruct.resultDataType == 0)
            {
                valueStr = QString("[Re(%1)]").arg(metaStruct.dataGroupName);
            }
            else if (metaStruct.resultDataType == 1)
            {
                valueStr = QString("[Im(%1)]").arg(metaStruct.dataGroupName);
            }
            else if (metaStruct.resultDataType == 2)
            {
                valueStr = QString("[mag(%1)]").arg(metaStruct.dataGroupName);
            }
            else if (metaStruct.resultDataType == 3)
            {
                valueStr = QString("[arg(%1)]").arg(metaStruct.dataGroupName);
            }
            else if (metaStruct.resultDataType == 4)
            {
                valueStr = QString("[%1]").arg(metaStruct.dataGroupName);
            }
            QString name = info->getCurveName().remove(QRegularExpression("\\[.*?]$")) + valueStr;
            item->setText(name);
            item->setToolTip(name);
            qobject_cast<QCPGraph*>(info->getCurveLineAddress())->setName(name);
            info->setCurveName(name);

            info->m_curveSettingData->m_resultDataName = name;
        }
        m_customPlot->replot();
    }

    void LineChartWindow::slot_updateUnit()
    {
        // 更新x轴单位
        QString labelX;
        if (m_autoXTitleText)
        {
            slot_autoGetXTitleText(labelX);
        }
        else
        {
            labelX = m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleText;
        }

        auto xUnit = m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_xAxisUnit;
        m_customPlot->xAxis->setLabel(labelX + "[" + xUnit + "]");

        // 更新y轴单位
        QStringList unitList;
        auto model = qobject_cast<QStandardItemModel*>(m_settings->getCurveNameListView()->model());
        for (auto row = 0; row < model->rowCount(); row++)
        {
            QStandardItem* item = model->item(row);

            const auto& info = getCurveInfoByItem(item);
            auto graph = info->getCurveLineAddress();
            if (graph == nullptr || !graph->visible())
            {
                continue;
            }
            QString unit;
            auto reder = info->getReader();
            int index = reder->getRealValueIndex(info->getValueIndex(), info->getValueComponent());

            if (index < 0 || index >= reder->getEachColUnitOfValue().size())
            {
                index = 0;
            }

            QList<std::tuple<int, int, QString>> yUnitList = m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_yAxisUnitList;
            auto array = reder->getStandardTable()->GetColumn(index + reder->getEachColNameOfKey().size());
            auto type = TextArrayMetaHander::getResultParaTypeFromArray(array);
            auto componentType = TextArrayMetaHander::getResultDataTypeFromArray(array);

            for (const auto& i : yUnitList)
            {
                if (std::get<0>(i) == type && std::get<1>(i) == componentType)
                {
                    unit = std::get<2>(i);
                    break;
                }
            }
            unit = unit.trimmed();

            if (!unit.compare("none", Qt::CaseInsensitive))
            {
                unit.clear();
            }
            if (info->getIsDB())
            {
                unit.insert(0, "dB");
            }
            if (unit.isEmpty())
            {
                continue;
            }
            if (!unitList.contains(unit, Qt::CaseInsensitive))
            {
                unitList.append(unit);
            }
        }
        if (unitList.empty())
        {
            m_yUnit = "";
        }
        else
        {
            m_yUnit = '[' + unitList.join(",") + ']';
        }
        QString label;
        if (m_autoYTitleText)
        {
            slot_autoGetYTitleText(label);
        }
        else
        {
            label = m_customPlot->yAxis->label().remove(QRegularExpression("\\[.+]"));
        }
        m_customPlot->yAxis->setLabel(label + m_yUnit);
        m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisDisplay()->m_titleText = label;
    }

    void LineChartWindow::slot_updateSelectedGraphState()
    {
        QList<Info2DPointer> curInfoList;

        for (auto curvePair : m_curveMap)
        {
            auto info = curvePair.second;
            if (info->getCurveLineAddress() == nullptr)
            {
                continue;
            }
            QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
            //if (graph->selected())
            if (!graph->selection().isEmpty())
            {
                curInfoList.append(info);
            }
        }

        int state = 0;
        // 设置框中选中的曲线发生改变->根据曲线信息更新m_settings
        if (!curInfoList.isEmpty())
        {
            state = 1;
            QString dataSources;
            for (const auto& info : curInfoList)
            {
                const auto& str = info->getDataSources();
                if (dataSources.isEmpty())
                {
                    dataSources = str;
                }
                else if (dataSources != str)
                {
                    dataSources.clear();
                    break;
                }
            }
            if (!dataSources.isEmpty())
            {
                // 方向图数据，且变量为theta/phi角度时才可启用 半功率波束宽度
                if (dataSources.contains("方向图数据") && m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit.toUpper()=="DEG")
                {
                    state = 2;
                }
                else if (dataSources.contains("驻波比数据"))
                {
                    state = 3;
                }
            }
        }
        emit signal_updateMeasureButtonState(state);
    }

    void LineChartWindow::slot_checkStandardCcurveState()
    {
        bool isShowStandardCcurveButton = false;
        for (auto curvePair : m_curveMap)
        {
            auto& info = curvePair.second;
            auto graph = info->getCurveLineAddress();
            if (graph == nullptr)
            {
                continue;
            }
            auto reader = info->getReader();
            int index = reader->getRealValueIndex(info->getValueIndex(), info->getValueComponent());

            if (index < 0 || index >= reader->getEachColUnitOfValue().size())
            {
                index = 0;
            }

            auto table = reader->getOriginalTable();
            auto array = table->GetColumn(index + reader->getEachColNameOfKey().size());
            TextArrayMetaStruct metaStruct;
            TextArrayMetaHander::getArrayMeta(array, metaStruct);
            switch (metaStruct.resultParaType)
            {
            case 0:
            case 10:
            case 11:
                isShowStandardCcurveButton = true;
                break;
            default:
                break;
            }
            if (isShowStandardCcurveButton)
            {
                break;
            }
        }
        emit signal_updateStandardCcurveState(isShowStandardCcurveButton);
    }

    void LineChartWindow::pyVariableAxisChanged(QList<int> allSelectedItemIndexList, int result, QString variableAxistCurrentText)
    {
        m_settings->pyVariableAxisChanged(allSelectedItemIndexList, result, variableAxistCurrentText);
    }

    void LineChartWindow::pyCurveNameClicked(QList<int> allSelectedItemIndexList)
    {
        m_settings->pyCurveNameClicked(allSelectedItemIndexList);
    }

    void LineChartWindow::pyFixedValueChanged(QList<int> allIndexList)
    {
        m_settings->pyFixedValueChanged(allIndexList);
    }

    void LineChartWindow::pyCurveNameCheckStateChanged(int index, int checkStatus)
    {
        m_settings->pyCurveNameCheckStateChanged(index, checkStatus);
    }

    void LineChartWindow::pyDataOperationChanged(bool isNormChecked, bool isDBChecked, bool isMathOperationChecked)
    {
        m_settings->pyDataOperationChanged(isNormChecked, isDBChecked, isMathOperationChecked);
    }

    void LineChartWindow::pyDataOperationChanged(int currentIndex)
    {
        m_settings->pyValueDataChanged(currentIndex);
    }

    void LineChartWindow::slot_lineChartSaveMainSettingData(int index,
        bool axiDisIsAutoName, QString axiDisTitleText, QString axiDisTitleFontColor, int axiDisTitleFontSize, QString axiDisAxisColor, int axiDisAxisThickness, double axiDisValuePrecision, QString axiDisAxisDigitColor, int axiDisAxisDigitSize,
        bool axiRangIsAutoRange, double axiRangMaxValue, double axiRangMinValue, bool axiRangIsAutoStepSize, double axiRangCustomStepSize,
        bool yAxiDisIsAutoName, QString yAxiDisTitleText, QString yAxiDisTitleFontColor, int yAxiDisTitleFontSize, QString yAxiDisAxisColor, int yAxiDisAxisThickness, double yAxiDisValuePrecision, QString yAxiDisAxisDigitColor, int yAxiDisAxisDigitSize,
        bool yAxiRangIsAutoRange, double yAxiRangMaxValue, double yAxiRangMinValue, bool yAxiRangIsAutoStepSize, double yAxiRangCustomStepSize,
        bool gridIsMainGridLineDisplay, QString gridMainGridLineColor, int gridMainGridLineStyle, double gridMainGridLineThickness, bool gridIsSecondaryGridLineDisplay, QString gridSecondaryGridLineColor, int gridSecondaryGridLineStyle, double gridSecondaryGridLineThickness,
        QString titleName, QString titleFontColor, int titleFontSize,
        QString legendFontColor, int legendFontSize, QString legendLineColor, int legendLineThickness,
        QString resultDataName, QString dataLineColor, int dataLineStyle, double dataLineThickness, bool isDisplaySymbol, int symbolStyle, double symbolSize, QString symbolColor)
    {
        LineChartCenterSettingData* tempData = m_centerSettingData;
        tempData->m_lineChartCoordinateSettingData->indexOfGraph = index;

        auto _xAxisDisplay = tempData->m_lineChartCoordinateSettingData->getXAxisDisplay();
        _xAxisDisplay->m_isAutoName = axiDisIsAutoName;
        _xAxisDisplay->m_titleText = axiDisTitleText;
        auto colorList = GlobalHelperInstance->convertStringToIntList(axiDisTitleFontColor);
        _xAxisDisplay->m_titleFontColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _xAxisDisplay->m_titleFontSize = axiDisTitleFontSize;
        colorList = GlobalHelperInstance->convertStringToIntList(axiDisAxisColor);
        _xAxisDisplay->m_axisColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _xAxisDisplay->m_axisThickness = axiDisAxisThickness;
        _xAxisDisplay->m_valuePrecision = axiDisValuePrecision;
        colorList = GlobalHelperInstance->convertStringToIntList(axiDisAxisDigitColor);
        _xAxisDisplay->m_axisDigitColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _xAxisDisplay->m_axisDigitSize = axiDisAxisDigitSize;

        auto _xAxisRange = tempData->m_lineChartCoordinateSettingData->getXAxisRange();
        _xAxisRange->m_isAutoRange = axiRangIsAutoRange;
        _xAxisRange->m_maxValue = axiRangMaxValue;
        _xAxisRange->m_minValue = axiRangMinValue;
        _xAxisRange->m_isAutoStepSize = axiRangIsAutoStepSize;
        _xAxisRange->m_customStepSize = axiRangCustomStepSize;

        auto _yAxisDisplay = tempData->m_lineChartCoordinateSettingData->getYAxisDisplay();
        _yAxisDisplay->m_isAutoName = yAxiDisIsAutoName;
        _yAxisDisplay->m_titleText = yAxiDisTitleText;
        colorList = GlobalHelperInstance->convertStringToIntList(yAxiDisTitleFontColor);
        _yAxisDisplay->m_titleFontColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _yAxisDisplay->m_titleFontSize = yAxiDisTitleFontSize;
        colorList = GlobalHelperInstance->convertStringToIntList(yAxiDisAxisColor);
        _yAxisDisplay->m_axisColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _yAxisDisplay->m_axisThickness = yAxiDisAxisThickness;
        _yAxisDisplay->m_valuePrecision = yAxiDisValuePrecision;
        colorList = GlobalHelperInstance->convertStringToIntList(yAxiDisAxisDigitColor);
        _yAxisDisplay->m_axisDigitColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _yAxisDisplay->m_axisDigitSize = yAxiDisAxisDigitSize;

        auto _yAxisRange = tempData->m_lineChartCoordinateSettingData->getYAxisRange();
        _yAxisRange->m_isAutoRange = yAxiRangIsAutoRange;
        _yAxisRange->m_maxValue = yAxiRangMaxValue;
        _yAxisRange->m_minValue = yAxiRangMinValue;
        _yAxisRange->m_isAutoStepSize = yAxiRangIsAutoStepSize;
        _yAxisRange->m_customStepSize = yAxiRangCustomStepSize;

        auto _grid = tempData->m_lineChartCoordinateSettingData->getGrid();
        _grid->m_isMainGridLineDisplay = gridIsMainGridLineDisplay;
        colorList = GlobalHelperInstance->convertStringToIntList(gridMainGridLineColor);
        _grid->m_mainGridLineColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _grid->m_mainGridLineStyle = gridMainGridLineStyle;
        _grid->m_mainGridLineThickness = gridMainGridLineThickness;
        _grid->m_isSecondaryGridLineDisplay = gridIsSecondaryGridLineDisplay;
        colorList = GlobalHelperInstance->convertStringToIntList(gridSecondaryGridLineColor);
        _grid->m_secondaryGridLineColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _grid->m_secondaryGridLineStyle = gridSecondaryGridLineStyle;
        _grid->m_secondaryGridLineThickness = gridSecondaryGridLineThickness;

        auto _title = tempData->m_lineChartCoordinateSettingData->getTitle();
        _title->m_titleName = titleName;
        colorList = GlobalHelperInstance->convertStringToIntList(titleFontColor);
        _title->m_titleFontColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _title->m_titleFontSize = titleFontSize;

        auto _legend = tempData->m_lineChartCoordinateSettingData->getLegend();
        colorList = GlobalHelperInstance->convertStringToIntList(legendFontColor);
        _legend->m_legendFontColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _legend->m_legendFontSize = legendFontSize;
        colorList = GlobalHelperInstance->convertStringToIntList(legendLineColor);
        _legend->m_legendLineColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _legend->m_legendLineThickness = legendLineThickness;

        auto _dataProperty = tempData->m_style2D_DataProperty;
        _dataProperty->m_resultDataName = resultDataName;
        colorList = GlobalHelperInstance->convertStringToIntList(dataLineColor);
        _dataProperty->m_dataLineColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));
        _dataProperty->m_dataLineStyle = dataLineStyle;
        _dataProperty->m_dataLineThickness = dataLineThickness;
        _dataProperty->m_isDisplaySymbol = isDisplaySymbol;
        _dataProperty->m_symbolStyle = symbolStyle;
        _dataProperty->m_symbolSize = symbolSize;
        colorList = GlobalHelperInstance->convertStringToIntList(symbolColor);
        _dataProperty->m_symbolColor = QColor(colorList.at(0), colorList.at(1), colorList.at(2));

        //this->slot_ChangeLineProperty(tempData);
    }

    void LineChartWindow::updateCurve(QStandardItem* item, Info2DPointer& info)
    {
        auto _graph = info->getGraph();
        auto _reader = info->getReader();
        QCPGraph* curveAdd = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        auto valueIndex = info->getValueIndex();
        auto componentIndex = info->getValueComponent();
        if (curveAdd == nullptr || _graph == nullptr || _reader == nullptr)
        {
            // TODO 警告
            return;
        }
        _reader->setScanParameterIndex(info->getScanParameterIndex());

        auto otherKeyData = info->getOtherKeyData();
        QVector<QVector<double>> others;
        for (auto i : otherKeyData)
        {
            others.append(QVector<double>{i});
        }
        _reader->setOtherKeyParameter(others);

        QList<Info2DPointer> newInfos;
        if (info->getIsNewData())
        {
            newInfos.append(info);
        }
        else
        {
            if (-1 != valueIndex)
            {
                QPair<int, int> tem{ valueIndex, componentIndex };
                _reader->getChosenLinesFromKey(QList<QPair<int, int>>{tem}, newInfos);
            }
        }
        if (newInfos.size() != 1)
        {
            // TODO 警告， 应该只产生一组数据
            return;
        }
        auto xData = newInfos[0]->getXData();
        auto yData = newInfos[0]->getYData();
        // qDebug() << "yData =" << yData;
        info->setXData(xData);
        info->setYData(yData);

        int index = _reader->getRealValueIndex(info->getValueIndex(), info->getValueComponent());
        auto table = _reader->getOriginalTable();
        if (index < 0 || index >= _reader->getEachColUnitOfValue().size())
        {
            index = 0;
        }
        auto array = table->GetColumn(index + _reader->getEachColNameOfKey().size());
        TextArrayMetaStruct metaStruct;
        TextArrayMetaHander::getArrayMeta(array, metaStruct);
        bool isPower = false;
        switch (metaStruct.resultParaType)
        {
        case 7:
        case 13:
        case 16:
        case 17:
        case 18:
            isPower = true;
            break;
        default:
            break;
        }

        // TODO 取对数和归一化 针对单条曲线
        normalizeAndLog(yData.second, info->getIsNormalized(), info->getIsDB(), isPower);
        if (info->getIsMathematicalOperations() && !info->getCalculationFormula().isEmpty())
        {
            // qDebug() << "info.getCalculationFormul: " << info.getCalculationFormula();
            auto calculationFormula = info->getCalculationFormula();
            auto resultData = compute(AnalyzeFormulaString(calculationFormula), qMakePair(yData.second, xData.second));
            if (!resultData.first.isEmpty())
            {
                auto& data = yData.second;
                if (resultData.first.size() == 1)
                {
                    data = QVector<double>(data.size(), resultData.first.first());
                }
                else
                {
                    for (int i = 0; i < data.size(); ++i)
                    {
                        if (i >= resultData.first.size())
                        {
                            break;
                        }
                        data[i] = resultData.first.at(i);
                    }
                }
            }
            else
            {
                qDebug() << "resultData size error!!!";
            }
        }


        // y轴单位处理
        auto keyCloNum = info->getReader()->getEachColNameOfKey().size();
        int groupId = info->getValueIndex();
        int componentId = info->getValueComponent();
        int realValueIndex = info->getReader()->getRealValueIndex(groupId, componentId);
        auto yArray = info->getReader()->getStandardTable()->GetColumn(keyCloNum + realValueIndex);
        TextArrayMetaStruct yArrayMetaStruct;
        TextArrayMetaHander::getArrayMeta(yArray, yArrayMetaStruct);
        auto yUnitType = yArrayMetaStruct.resultParaType;
        auto yUnit = yArrayMetaStruct.unit;
        auto componentType = yArrayMetaStruct.resultDataType;
        auto& infoYUnit = info->m_yAxisUnit;
        std::get<0>(infoYUnit) = yUnitType;
        std::get<1>(infoYUnit) = componentType;
        std::get<2>(infoYUnit) = yUnit;

        bool needDoUnitConversion = false;

        QList<std::tuple<int, int, QString>> newYAxisUnitList = m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList;

        bool hasSameType = false;
        for (const auto& i : newYAxisUnitList)
        {
            if (std::get<0>(i) == yUnitType && std::get<1>(i) == componentType)
            {
                hasSameType = true;
                needDoUnitConversion = true; // 已有该类型可能需要单位转换
            }
        }

        if (!hasSameType) // 可能产生新类型（如点击 幅度相位实部虚部）
        {
            m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList.append(std::make_tuple(yUnitType, componentType, yUnit)); // 使用该曲线的y轴单位
        }

        if (needDoUnitConversion) // 进行单位转换
        {
            doInfoUnitConversion(info);
        }




        curveAdd->setData(xData.second, yData.second);
        curveAdd->setName(info->getCurveName());
        item->setText(info->getCurveName());
        item->setToolTip(info->getCurveName());

        slot_adaptiveRange();
    }

    bool LineChartWindow::eventFilter(QObject* watched, QEvent* event)
    {
        // 屏蔽标记窗口中的滚轮响应到画布上
        if (event->type() == QEvent::Wheel && (watched == m_tracerPropertyWidget || watched == m_measureTableWidget))
        {
            event->accept();
            return true;
        }
        return false;
    }

    QQueue<QString> LineChartWindow::AnalyzeFormulaString(QString& str)
    {
        auto getPriorityFunc = [](QChar c)
            {
                int priority = 0;
                if (c == '+' || c == '-')
                {
                    priority = 1;
                }
                else if (c == '*' || c == '/')
                {
                    priority = 2;
                }
                else if (c == '^')
                {
                    priority = 3;
                }
                return priority;
            };
        // str.remove(" ");
        QStack<QChar> stack;
        QQueue<QString> queue;
        QString s;
        QChar previousChar;
        int count = 0;
        for (auto c : str)
        {
            if (count > 0 && (c != '(' && c != ')'))
            {
                s.append(c);
                previousChar = c;
                continue;
            }
            if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^')
            {
                if (c == '-')
                {
                    if (s.isEmpty() && previousChar != ')')
                    {
                        s.append(c);
                        previousChar = c;
                        continue;
                    }
                    else if (s.contains(QRegularExpression("^-+$")))
                    {
                        qDebug() << "- error!!!";
                        return QQueue<QString>();
                    }
                }
                if (!s.isEmpty())
                {
                    s = s.trimmed();
                    if (!s.isEmpty())
                    {
                        queue.enqueue(s);
                    }
                    s.clear();
                }
                if (stack.isEmpty())
                {
                    stack.push(c);
                }
                else
                {
                    int priority = getPriorityFunc(c);
                    int lastPriority = getPriorityFunc(stack.last());
                    while (priority <= lastPriority)
                    {
                        queue.enqueue(stack.pop());
                        if (stack.isEmpty())
                        {
                            break;
                        }
                        lastPriority = getPriorityFunc(stack.last());
                    }
                    stack.push(c);
                }
            }
            else if (c == '(')
            {
                if (s.isEmpty())
                {
                    stack.push(c);
                }
                else
                {
                    ++count;
                    s.append(c);
                }
            }
            else if (c == ')')
            {
                if (count == 0)
                {
                    if (stack.contains('('))
                    {
                        if (!s.isEmpty())
                        {
                            s = s.trimmed();
                            if (!s.isEmpty())
                            {
                                queue.enqueue(s);
                            }
                            s.clear();
                        }
                        while (stack.last() != '(')
                        {
                            queue.enqueue(stack.pop());
                        }
                        stack.pop();
                    }
                    else
                    {
                        qDebug() << ") error!!!";
                        return QQueue<QString>();
                    }
                }
                else if (count > 0)
                {
                    --count;
                    s.append(c);
                }
            }
            else
            {
                s.append(c);
            }
            previousChar = c;
        }
        if (stack.contains('(') || stack.contains(')'))
        {
            qDebug() << "( or ) error!!!";
            return QQueue<QString>();
        }
        else
        {
            if (!s.isEmpty())
            {
                s = s.trimmed();
                if (!s.isEmpty())
                {
                    queue.enqueue(s);
                }
            }
            while (!stack.isEmpty())
            {
                queue.enqueue(stack.pop());
            }
        }
        // qDebug() << queue;
        return queue;
    }

    CalculationData LineChartWindow::Symbolics(const CalculationData& first, const CalculationData& second, const QString& computeOperator)
    {
        CalculationData v;
        auto func = GetSymbolicOperationFunc(computeOperator);
        if (func != nullptr)
        {
            if (func({ first, second }, v))
            {
                // qDebug() << "v: " << v;
            }
            else
            {
                qDebug() << computeOperator << " compute is error!!!";
                return CalculationData();
            }
        }
        else
        {
            qDebug() << computeOperator << " func is nullptr!!!";
            return CalculationData();
        }
        return v;
    }

    CalculationData LineChartWindow::Formula(const QString& str, const CalculationData& selfData)
    {
        CalculationData result;
        QRegularExpression reg("^(.+?)\\((.+)\\)$");
        auto match = reg.match(str);
        if (match.hasMatch())
        {
            // qDebug() << match.captured();
            QString name = match.captured(1);
            QString s = match.captured(2);
            int count = 0;
            QString sss;
            QStringList sList;
            for (const auto& sT : s)
            {
                if (sT == '(')
                {
                    ++count;
                    sss.append(sT);
                }
                else if (sT == ')')
                {
                    --count;
                    sss.append(sT);
                }
                else if (sT == ',')
                {
                    if (count == 0)
                    {
                        sList.append(sss);
                        sss.clear();
                    }
                    else
                    {
                        sss.append(sT);
                    }
                }
                else
                {
                    sss.append(sT);
                }
            }
            if (!sss.isEmpty())
            {
                sList.append(sss);
            }
            if (sList.size() > 2)
            {
                qDebug() << "size error!!!";
                return CalculationData();
            }
            QVector<CalculationData> value;
            for (auto& sTmp : sList)
            {
                auto result = compute(AnalyzeFormulaString(sTmp), selfData);
                if (result.first.isEmpty())
                {
                    qDebug() << "compute is error!!!";
                    return CalculationData();
                }
                else
                {
                    value.append(result);
                }
            }
            auto func = GetFormulaFunc(name.toLower());
            if (func != nullptr)
            {
                if (func(value, result))
                {
                    // qDebug() << "result: " << result;
                }
                else
                {
                    qDebug() << name << " compute is error!!!";
                    return CalculationData();
                }
            }
            else
            {
                qDebug() << name << " func is nullptr!!!";
                return CalculationData();
            }
        }
        else
        {
            qDebug() << "not match!!!";
            return CalculationData();
        }
        return result;
    }

    CalculationData LineChartWindow::compute(QQueue<QString> queue, const CalculationData& selfData)
    {
        if (queue.isEmpty() || selfData.first.isEmpty())
        {
            qDebug() << "data is empty!!!";
            return CalculationData();
        }
        const QStringList& formulaList = GetFormulaFuncNames();
        const QStringList& constantList = GetConstantNames();
        const QStringList& curveList = GetCurveNames();
        QStack<CalculationData> stack;
        for (auto& str : queue)
        {
            if (str == '+' || str == '-' || str == '*' || str == '/' || str == '^')
            {
                if (stack.size() < 2)
                {
                    qDebug() << "operations Number error!!!";
                    return CalculationData();
                }
                auto b = stack.pop();
                auto a = stack.pop();
                auto v = Symbolics(a, b, str);
                if (v.first.isEmpty())
                {
                    qDebug() << "Symbolics error!!!";
                    return CalculationData();
                }
                else
                {
                    stack.push(std::move(v));
                }
            }
            else
            {
                auto aaa = QRegularExpression("^(" + formulaList.join(")|(") + ")");
                if (str.toLower().contains(aaa))
                {
                    auto result = Formula(str, selfData);
                    if (result.first.isEmpty())
                    {
                        qDebug() << "Formula error!!!";
                        return CalculationData();
                    }
                    else
                    {
                        stack.push(std::move(result));
                    }
                }
                else if (constantList.contains(str, Qt::CaseInsensitive))
                {
                    auto result = GetConstanValue(str.toLower());
                    if (result == 0)
                    {
                        qDebug() << "GetConstanValue error!!!";
                        return CalculationData();
                    }
                    else
                    {
                        stack.push(CalculationData({ result }, {}));
                    }
                }
                else if (curveList.contains(str, Qt::CaseInsensitive))
                {
                    auto result = GetCurveData(str, selfData);
                    if (result.first.isEmpty())
                    {
                        qDebug() << "GetCurveData error!!!";
                        return CalculationData();
                    }
                    else
                    {
                        stack.push(std::move(result));
                    }
                }
                else
                {
                    bool isDouble = false;
                    double value = str.toDouble(&isDouble);
                    if (isDouble)
                    {
                        stack.push(CalculationData({ value }, {}));
                    }
                    else
                    {
                        if (str.right(1) == "%")
                        {
                            double value = str.left(str.size() - 1).toDouble(&isDouble);
                            if (isDouble)
                            {
                                stack.push(CalculationData({ value / 100 }, {}));
                            }
                        }
                    }
                    if (!isDouble)
                    {
                        qDebug() << "not is number!!!";
                        return CalculationData();
                    }
                }
            }
        }
        if (stack.size() != 1)
        {
            qDebug() << "formula error!!!";
            return CalculationData();
        }
        // qDebug() << "queue: " << queue << "stack: " << stack;
        return stack.pop();
    }

    QStringList LineChartWindow::GetCurveNames()
    {
        QStringList names;
        names.append("self");
        for (int i = 0; i < m_customPlot->graphCount(); ++i)
        {
            auto graph = m_customPlot->graph(i);
            if (!graph->selected())
            {
                names.append(graph->name().toLower().trimmed());
            }
        }
        return names;
    }

    CalculationData LineChartWindow::GetCurveData(const QString& curveName, const CalculationData& selfData)
    {
        if (curveName == "self")
        {
            return selfData;
        }
        CalculationData data;
        for (int i = 0; i < m_customPlot->graphCount(); ++i)
        {
            auto graph = m_customPlot->graph(i);
            if (curveName.compare(graph->name(), Qt::CaseInsensitive) == 0)
            {
                const auto& graphData = graph->data();
                if (selfData.first.isEmpty())
                {
                    for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
                    {
                        data.first.append(iter->value);
                        data.second.append(iter->key);
                    }
                    break;
                }
                bool hasData = false;
                auto keyRange = graphData->keyRange(hasData);
                if (!hasData)
                {
                    break;
                }
                // 只取与selfData交集的部分，并且插值计算交集中非原始数据的key-value
                for (double key : selfData.second)
                {
                    if (keyRange.contains(key))
                    {
                        double value = caculateGraphValueByKey(key, graphData);
                        data.first.append(value);
                        data.second.append(key);
                    }
                }
                break;
            }
        }
        return data;
    }

    void LineChartWindow::addNewGraphByOpenProject(Info2DPointer& info, QString params, bool isAutoName)
    {
        QCPGraph* gta = m_customPlot->addGraph();
        // 设置颜色
        auto index = m_graphs.size() % m_colorList.size();
        auto color = m_colorList.at(index);
        QPen pen;
        pen.setWidth(2);
        pen.setColor(color);
        gta->setPen(pen);

        m_graphs.append(gta);
        info->setCurveLineAddress(gta); // 记录曲线地址
        if (!GlobalHelperInstance->getIsOpenProject())
            info->setInformationID(WindowTotalDataInstance->getGraph2DInformationMaxID());
        WindowTotalDataInstance->appendInfomationCurve2DBasical(info);

        QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        graph->setData(info->getXData().second, info->getYData().second); // 设置原始数据

        if (!info->getIsNewData()) // 不是新数据才需要记录，是新数据已经记录过了
        {
            // x单位信息记录到info
            auto xArray = info->getReader()->getStandardTable()->GetColumn(info->getScanParameterIndex());
            TextArrayMetaStruct xArrayMetaStruct;
            TextArrayMetaHander::getArrayMeta(xArray, xArrayMetaStruct);
            auto xUnitType = xArrayMetaStruct.resultParaType;
            auto xUnit = xArrayMetaStruct.unit;
            info->m_xAxisType = xUnitType;
            info->m_xAxisUnit = xUnit;


            // y单位信息记录到info
            auto keyCloNum = info->getReader()->getEachColNameOfKey().size();
            int groupId = info->getValueIndex();
            int componentId = info->getValueComponent();
            int realValueIndex = info->getReader()->getRealValueIndex(groupId, componentId);
            auto yArray = info->getReader()->getStandardTable()->GetColumn(keyCloNum + realValueIndex);
            TextArrayMetaStruct yArrayMetaStruct;
            TextArrayMetaHander::getArrayMeta(yArray, yArrayMetaStruct);
            auto yUnitType = yArrayMetaStruct.resultParaType;
            auto yUnit = yArrayMetaStruct.unit;
            auto componentType = yArrayMetaStruct.resultDataType;
            auto& infoYUnit = info->m_yAxisUnit;
            std::get<0>(infoYUnit) = yUnitType;
            std::get<1>(infoYUnit) = componentType;
            std::get<2>(infoYUnit) = yUnit;


            bool needDoUnitConversion = false;


            if (m_coodinateSetting->getXAxisDisplay()->m_xUnitType == -1) // 没有添加过曲线
            {
                m_coodinateSetting->getXAxisDisplay()->m_xUnitType = xUnitType; // 如果为-2，表面曲线没有单位
                m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit = xUnit;
            }
            else
            {
                needDoUnitConversion = true;
            }

            QList<std::tuple<int, int, QString>> newYAxisUnitList = m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList;

            bool hasSameType = false;
            for (const auto& i : newYAxisUnitList)
            {
                if (std::get<0>(i) == yUnitType && std::get<1>(i) == componentType)
                {
                    hasSameType = true;
                    needDoUnitConversion = true; // 已有该类型可能需要单位转换
                }
            }

            if (!hasSameType)
            {
                m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList.append(std::make_tuple(yUnitType, componentType, yUnit)); // 使用该曲线的y轴单位
            }

            if (needDoUnitConversion) // 进行单位转换
            {
                doInfoUnitConversion(info);
            }

        }
        m_unit = '[' + m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit + ']';

        gta->setName(info->getCurveName());
        if (info->getXData().second.size() == 1)
        {
            auto scatterStyle = gta->scatterStyle();
            scatterStyle.setShape(QCPScatterStyle::ssDisc);
            scatterStyle.setPen(color);
            gta->setScatterStyle(scatterStyle);
        }
        // 添加曲线名字
        QStandardItem* item = m_settings->addCurveToList(info->getCurveName(), params);
        {
            // m_curveMap[item] = info; // 记录下来以备查找
            addCurveItemInfoPair(item, info);
            info->setSidebarItem(item);
            if (isAutoName)
            {
                item->setData(true);
            }
        }

        QString label;
        if (m_autoXTitleText)
        {
            slot_autoGetXTitleText(label);
        }
        else
        {
            label = m_customPlot->xAxis->label().remove(QRegularExpression("\\[.+]"));
        }
        m_customPlot->xAxis->setLabel(label + m_unit);
        m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleText = label;

        // 更新设置窗口xy轴范围
        slot_adaptiveRange();
        updateAxisRange();
    }
    void LineChartWindow::addNewGraph(Info2DPointer& info, QString params, bool isAutoName)
    {
        // InfomationCurve2DBasical info = info1;
        QCPGraph* gta = m_customPlot->addGraph();
        // gta->setSelectable(QCP::SelectionType::stNone);
        // 设置颜色
        auto index = m_graphs.size() % m_colorList.size();
        auto color = m_colorList.at(index);
        QPen pen;
        pen.setWidth(2);
        pen.setColor(color);
        gta->setPen(pen);

        m_graphs.append(gta);
        // qDebug() << " info.getYData().second =" << info.getYData().second;
        info->setCurveLineAddress(gta); // 记录曲线地址
        if (!GlobalHelperInstance->getIsOpenProject())
            info->setInformationID(WindowTotalDataInstance->getGraph2DInformationMaxID());
        WindowTotalDataInstance->appendInfomationCurve2DBasical(info);

        QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        graph->setData(info->getXData().second, info->getYData().second); // 设置原始数据

        if (!info->getIsNewData()) // 不是新数据才需要记录，是新数据已经记录过了
        {
            // x单位信息记录到info
            auto xArray = info->getReader()->getStandardTable()->GetColumn(info->getScanParameterIndex());
            TextArrayMetaStruct xArrayMetaStruct;
            TextArrayMetaHander::getArrayMeta(xArray, xArrayMetaStruct);
            auto xUnitType = xArrayMetaStruct.resultParaType;
            auto xUnit = xArrayMetaStruct.unit;
            info->m_xAxisType = xUnitType;
            info->m_xAxisUnit = xUnit;


            // y单位信息记录到info
            auto keyCloNum = info->getReader()->getEachColNameOfKey().size();
            int groupId = info->getValueIndex();
            int componentId = info->getValueComponent();
            int realValueIndex = info->getReader()->getRealValueIndex(groupId, componentId);
            auto yArray = info->getReader()->getStandardTable()->GetColumn(keyCloNum + realValueIndex);
            TextArrayMetaStruct yArrayMetaStruct;
            TextArrayMetaHander::getArrayMeta(yArray, yArrayMetaStruct);
            auto yUnitType = yArrayMetaStruct.resultParaType;
            auto yUnit = yArrayMetaStruct.unit;
            auto componentType = yArrayMetaStruct.resultDataType;
            auto& infoYUnit = info->m_yAxisUnit;
            std::get<0>(infoYUnit) = yUnitType;
            std::get<1>(infoYUnit) = componentType;
            std::get<2>(infoYUnit) = yUnit;
            auto newXAxisUnit = m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit;
            if (!newXAxisUnit.isEmpty())
            {
                info->m_xAxisUnit = m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit;
                info->m_xAxisType = m_coodinateSetting->getXAxisDisplay()->m_xUnitType;
            }

            bool needDoUnitConversion = false;


            if (m_coodinateSetting->getXAxisDisplay()->m_xUnitType == -1) // 没有添加过曲线
            {
                m_coodinateSetting->getXAxisDisplay()->m_xUnitType = xUnitType; // 如果为-2，表面曲线没有单位
                m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit = xUnit;
            }
            else
            {
                needDoUnitConversion = true;
            }

            QList<std::tuple<int, int, QString>> newYAxisUnitList = m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList;

            bool hasSameType = false;
            for (const auto& i : newYAxisUnitList)
            {
                if (std::get<0>(i) == yUnitType && std::get<1>(i) == componentType)
                {
                    hasSameType = true;
                    needDoUnitConversion = true; // 已有该类型可能需要单位转换
                }
            }

            if (!hasSameType)
            {
                m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList.append(std::make_tuple(yUnitType, componentType, yUnit)); // 使用该曲线的y轴单位
            }

            if (needDoUnitConversion) // 进行单位转换
            {
                m_execSuccessFlag = true;
                doInfoUnitConversion(info);
                if (!m_execSuccessFlag)
                {
                    return;
                }
            }

        }
        // else
        //{
        //     doInfoUnitConversion(info);
        // }

        m_unit = '[' + m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit + ']';

        gta->setName(info->getCurveName());

        auto dataProperty = new Style2D_DataProperty(this);
        dataProperty->m_resultDataName = info->getCurveName();
        if (info->getXData().second.size() == 1)
        {
            auto scatterStyle = gta->scatterStyle();
            scatterStyle.setShape(QCPScatterStyle::ssDisc);
            scatterStyle.setPen(color);
            gta->setScatterStyle(scatterStyle);

            dataProperty->m_isDisplaySymbol = true;
            dataProperty->m_symbolStyle = 4;
        }
        // 每个m_customPlot的横纵轴与文件整体有关，不与单条曲线有关
        // m_customPlot->xAxis->setLabel(x.first);
        // m_customPlot->yAxis->setLabel(y.first);
        // m_customPlot->legend->setVisible(true);
        //
        // info->setCurveLineAddress(gta); // 记录曲线地址

        // 添加曲线名字
        QStandardItem* item = m_settings->addCurveToList(info->getCurveName(), params);
        {
            // m_curveMap[item] = info; // 记录下来以备查找
            addCurveItemInfoPair(item, info);
            info->setSidebarItem(item);
            // QSignalBlocker blocker(m_settings->getCurveNameListView()->model());
            //  QSignalBlocker blocker1(m_settings->getCurveNameListView()->selectionModel());
            // item->setCheckState(Qt::Checked);
            if (isAutoName)
            {
                item->setData(true);
            }
        }

        QString label;
        if (m_autoXTitleText)
        {
            slot_autoGetXTitleText(label);
        }
        else
        {
            label = m_customPlot->xAxis->label().remove(QRegularExpression("\\[.+]"));
        }
        // m_unit = '[' + info->getReader()->getEachColUnitOfKey().at(info->getReader()->getScanParameterIndex()).trimmed() + ']';
        m_customPlot->xAxis->setLabel(label + m_unit);
        m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_titleText = label;
        // m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisDisplay()->m_xAxisUnit = m_unit;

        // 生成曲线数据
        // TODO Style2D_DataProperty 初始化赋值
        // dataProperty->m_resultDataName = info->getCurveName();
        // dataProperty->m_dataLineColor = color;
        // dataProperty->m_dataLineStyle = Qt::PenStyle::SolidLine;
        // dataProperty->m_dataLineThickness = 2;
        // dataProperty->m_symbolStyle = QCPScatterStyle::ssDisc;
        // dataProperty->m_symbolSize = 1;//可能不对
        // dataProperty->m_symbolColor = color;
        dataProperty->m_dataLineColor = color;
        dataProperty->m_symbolColor = color;
        m_centerSettingData->m_style2D_DataProperty = dataProperty;
        info->setLineChartCenterSettingData(m_centerSettingData);
        info->setCurvePropertyData(dataProperty);

        QCoreApplication::processEvents(); // 让 UI 有机会更新,防止获取高度axisRect()->rect().height()失败
        QTimer::singleShot(0, this, [=]() {
            adjustLegendColumns();
            });
        // 更新设置窗口xy轴范围
        slot_adaptiveRange();

        updateAxisRange();

        // slot_updateCurveData({item}, info);
    }

    QList<CalculationData> LineChartWindow::GetCurveDataByNames(const QList<QString>& names)
    {
        QList<CalculationData> results;
        QList<QCPGraph*> graphs;
        QVector<double> keyData;
        for (const auto& name : names)
        {
            for (int i = 0; i < m_customPlot->graphCount(); ++i)
            {
                auto graph = m_customPlot->graph(i);
                if (name.compare(graph->name(), Qt::CaseInsensitive) == 0)
                {
                    graphs.append(graph);
                    const auto& graphData = graph->data();
                    for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
                    {
                        keyData.append(iter->key);
                    }
                }
            }
        }
        std::set set(keyData.begin(), keyData.end());                                  // 保持数据顺序去重
        keyData = QVector<double>::fromStdVector(std::vector(set.begin(), set.end())); // 获取最大key并集
        for (auto graph : graphs)
        {
            const auto& graphData = graph->data();
            CalculationData data;
            bool hasData = false;
            auto keyRange = graphData->keyRange(hasData);
            if (!hasData)
            {
                results.append(std::move(data));
                continue;
            }
            // 获取各曲线数据，并插值计算交集中的非原始数据的key-value数据
            for (double key : keyData)
            {
                if (keyRange.contains(key))
                {
                    double value = caculateGraphValueByKey(key, graphData);
                    data.first.append(value);
                    data.second.append(key);
                }
            }
            results.append(std::move(data));
        }
        return results;
    }

    void LineChartWindow::doInfoUnitConversion(Info2DPointer& info)
    {
        const auto& oldXUnit = info->m_xAxisUnit;
        const auto& oldXUnitType = info->m_xAxisType;
        auto newXAxisUnit = m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit;

        auto& yUnitAxisData = info->m_yAxisUnit;
        int yUnitType = std::get<0>(yUnitAxisData);
        int componentType = std::get<1>(yUnitAxisData);
        QString oldYUnit = std::get<2>(yUnitAxisData);
        QList<std::tuple<int, int, QString>> newYAxisUnitList = m_coodinateSetting->getYAxisDisplay()->m_yAxisUnitList;

        bool xNeedConvert = false, yNeedConvert = false;
        if (oldXUnit != newXAxisUnit)
        {
            xNeedConvert = true;
        }

        QString newYUnit = "";
        for (const auto& i : newYAxisUnitList)
        {
            if (std::get<0>(i) == yUnitType && std::get<1>(i) == componentType && std::get<2>(i) != oldYUnit)
            {
                yNeedConvert = true;
                newYUnit = std::get<2>(i);
                break;
            }
        }

        if (!xNeedConvert && !yNeedConvert)
        {
            return; // xy轴单位没有变化，不需要转换
        }

        QCPGraph* graph = qobject_cast<QCPGraph*>(info->getCurveLineAddress());
        auto dataContainer = graph->data();
        int dataSize = dataContainer->size();
        QVector<double> oldXData(dataSize), oldYData(dataSize);
        for (int i = 0; i < dataSize; ++i)
        {
            auto d = dataContainer->at(i);
            oldXData[i] = d->key;
            oldYData[i] = d->value;
        }

        if (xNeedConvert)
        {
            QVector<double> newXData;
            bool isSuc = UnitHelper::doKeyUnitConvert(info->m_xAxisType, oldXData, oldXUnit, newXAxisUnit, newXData);
            if (!isSuc)
            {
                if (!GlobalHelperInstance->getIsOpenProject())
                    EDialogMsgResult _result = IdaDialogMsg::showDialog(this, QString("单位转换失败."), EDialogMsg::Error, tr("单位转换失败"));
                m_execSuccessFlag = false;
                return;
            }
            graph->setData(newXData, oldYData);
            info->m_xAxisUnit = newXAxisUnit;//更新x轴单位
            //m_unit = '[' + m_coodinateSetting->getXAxisDisplay()->m_xAxisUnit + ']';//可以不需要
        }

        if (yNeedConvert)
        {
            QVector<double> newYData;
            bool isSuc = UnitHelper::doValueUnitConvert(yUnitType, componentType, oldYData, oldYUnit, newYUnit, newYData);
            if (!isSuc)
            {
                if (!GlobalHelperInstance->getIsOpenProject())
                    EDialogMsgResult _result = IdaDialogMsg::showDialog(this, QString("单位转换失败."), EDialogMsg::Error, tr("单位转换失败"));
                m_execSuccessFlag = false;
                return;
            }

            std::get<2>(yUnitAxisData) = newYUnit; // 更新y轴单位

            if (xNeedConvert)
            {
                QVector<double> xData(dataSize); // x轴可能已经做了单位转换
                for (int i = 0; i < dataSize; ++i)
                {
                    auto d = dataContainer->at(i);
                    xData[i] = d->key;
                }

                graph->setData(xData, newYData);
            }
            else
            {
                graph->setData(oldXData, newYData);
            }
        }
    }

    void LineChartWindow::slot_closeTree(const QList<QStandardItem*>& items)
    {
        QList<QCPGraph*> itemToDelete;
        for (auto treeItem : items)
        {
            for (auto info : m_curveMap)
            {
                if (info.second->getProjectTreeSourceItem() == treeItem)
                {
                    QCPGraph* graph = qobject_cast<QCPGraph*>(info.second->getCurveLineAddress());
                    itemToDelete.append(graph);
                }
            }
        }
        slot_removeGraphs(itemToDelete);
    }
    void LineChartWindow::slot_localScope(double rangeLower, double rangeUpper, const QList<QString>& selectNames, bool& execFlag, bool edit)
    {
        if (selectNames.isEmpty())
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("未选择曲线！"), EDialogMsg::Error, QStringLiteral("局部范围错误"));
            execFlag = false;
            return;
        }
        if (rangeLower > rangeUpper)
        {
            auto _res = IdaDialogMsg::showDialog(nullptr, QStringLiteral("起始值应小于终止值"), EDialogMsg::Error, QStringLiteral("局部范围错误"));
            execFlag = false;
            return;
        }

        // 判断起始值和终止值是否在“选择曲线”所选的多条或单条曲线数据的最小值和最大值范围内
        QSet<QString> showCurves;
        for (const auto& name : selectNames)
        {
            for (const auto& info : m_curveMap)
            {
                auto graph = qobject_cast<QCPGraph*>(info.second->getCurveLineAddress());
                if (graph == nullptr || graph->name() != name)
                {
                    continue;
                }
                bool hasRange = false;
                auto tmpRange = graph->getKeyRange(hasRange);
                if (GlobalHelperInstance->isDoubleValueInRange(rangeLower, tmpRange.lower, tmpRange.upper) && GlobalHelperInstance->isDoubleValueInRange(rangeUpper, tmpRange.lower, tmpRange.upper))
                {
                    showCurves.insert(name);
                }
            }
        }

        // 是否在设置的起始值到终止值范围内都存在数据
        if (showCurves.size() != selectNames.size())
        {
            IdaDialogMsg::showDialog(nullptr, QStringLiteral("局部范围设置值超过当前所选曲线的变量范围，请修改设置值。"), EDialogMsg::Warning, QStringLiteral("局部范围警告"));
            execFlag = false;
            return;
        }

        if (showCurves.isEmpty())
        {
            return;
        }

        QSet<QString> allCurveNames;
        for (int i = 0; i < m_customPlot->graphCount(); ++i)
        {
            auto graph = m_customPlot->graph(i);
            allCurveNames.insert(graph->name());
        }

        for (const auto& name : showCurves)
        {
            for (const auto& info : m_curveMap)
            {
                auto graph = qobject_cast<QCPGraph*>(info.second->getCurveLineAddress());
                if (graph == nullptr)
                {
                    continue;
                }
                if (name.compare(graph->name(), Qt::CaseInsensitive) == 0)
                {
                    QString params = QString::number(DataAnalysisType::LocalRange) + "," + QString::number(rangeLower) + "," + QString::number(rangeUpper) + "," + name;

                    bool hasRange = false;
                    auto tmpRange = graph->getKeyRange(hasRange);
                    if (!hasRange)
                    {
                        break;
                    }
                    tmpRange.lower = tmpRange.lower > rangeLower ? tmpRange.lower : rangeLower;
                    tmpRange.upper = tmpRange.upper < rangeUpper ? tmpRange.upper : rangeUpper;
                    if (tmpRange.lower > tmpRange.upper)
                    {
                        break;
                    }
                    QVector<double> keyData, valueData;
                    const auto& graphData = graph->data();
                    // 获取范围内的key与value数据
                    for (auto iter = graphData->begin(); iter != graphData->end(); ++iter)
                    {
                        double key = iter->key;
                        if (tmpRange.contains(key))
                        {
                            keyData.append(key);
                            valueData.append(iter->value);
                        }
                    }
                    // 最小范围值若不是原始数据，插值加入
                    if (!keyData.contains(tmpRange.lower))
                    {
                        keyData.insert(0, tmpRange.lower);
                        valueData.insert(0, caculateGraphValueByKey(tmpRange.lower, graphData));
                    }
                    // 最大范围值若不是原始数据，插值加入
                    if (!keyData.contains(tmpRange.upper))
                    {
                        keyData.append(tmpRange.upper);
                        valueData.append(caculateGraphValueByKey(tmpRange.upper, graphData));
                    }

                    if (edit)
                    {
                        auto editGraph = m_customPlot->selectedGraphs().front();
                        for (auto& tmpinfo : m_curveMap)
                        {
                            auto tmpgraph = qobject_cast<QCPGraph*>(tmpinfo.second->getCurveLineAddress());
                            if (tmpgraph == nullptr)
                            {
                                continue;
                            }
                            if (tmpgraph == editGraph)
                            {
                                QString newCurveName = info.second->getCurveName() + "_局部范围_" + QString::number(rangeLower) + "_" + QString::number(rangeUpper);
                                //QString finalName = autoIncrementName(newCurveName);
                                QString finalName = newCurveName +"_"+ QString::number(m_localRangeId);
                                //while (getHasSameName(finalName))
                                //{
                                //    finalName += "_1";
                                //}

                                tmpinfo.second->setCurveName(finalName);

                                tmpinfo.second->getXDataPointer()->second = std::move(keyData);
                                tmpinfo.second->getYDataPointer()->second = std::move(valueData);

                                tmpinfo.second->setIsNewData(true);
                                tmpinfo.second->setValueIndex(0);

                                tmpinfo.first->setData(params, Qt::UserRole + 3);
                                //m_customPlot->replot();
                                updateCurve(tmpinfo.first, tmpinfo.second);
                                break;
                            }
                        }
                    }
                    else
                    {
                        Info2DPointer dataInfo = Info2DPointer::create(*info.second);
                        dataInfo->getXDataPointer()->second = std::move(keyData);
                        dataInfo->getYDataPointer()->second = std::move(valueData);
                        dataInfo->getYDataPointer()->first = "局部范围";

                        QString newCurveName = info.second->getCurveName() + "_局部范围_" + QString::number(rangeLower) + "_" + QString::number(rangeUpper);
                    	//QString finalName = autoIncrementName(newCurveName);
                        QString finalName = newCurveName + "_" + QString::number(++m_localRangeId);
                        while (getHasSameName(finalName))
                        {
                            finalName += "_1";
                        }

                    	//QString finalName = GlobalHelperInstance->autoIncreaseName(allCurveNames, newCurveName);
                        dataInfo->setCurveName(finalName);

                        dataInfo->setIsNewData(true);
                        dataInfo->setValueIndex(0);
                        dataInfo->setGraph(this);

                        /*QString tmpDataSource = info.second->getCurveName();
                        slot_getSidebarCurveDataSource(tmpDataSource);
                        dataInfo->setDataSources(tmpDataSource);*/
                        dataInfo->setDataSources(QString());
                        this->addNewGraph(dataInfo, params);
                        m_addCurveInfo.append(dataInfo);
                        break;
                    }
                        
                }
            }
        }
    }

    void LineChartWindow::updateAxisRange()
    {
        if (m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_isAutoRange)
        {
            auto xRange = m_customPlot->xAxis->range();
            m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_minValue = xRange.lower;
            m_centerSettingData->m_lineChartCoordinateSettingData->getXAxisRange()->m_maxValue = xRange.upper;
        }
        if (m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_isAutoRange)
        {
            auto yRange = m_customPlot->yAxis->range();
            m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_minValue = yRange.lower;
            m_centerSettingData->m_lineChartCoordinateSettingData->getYAxisRange()->m_maxValue = yRange.upper;
        }

    }


    int LineChartWindow::getCustomRangePlotMaxIndex()
    {
        return m_customRangePlotMaxIndex++;
    }

    QHash<int, QString> LineChartWindow::getMarkerNameMap()
    {
        QHash<int, QString> map;
        for (int i = 0; i < m_tracerPropertyWidget->rowCount(); ++i)
        {
            auto t = m_tracerPropertyWidget->item(i, 0)->data(QVariant::UserType).value<LineChartTracer*>();
            map.insert(i, t->GetName());
        }
        return map;
    }

} // namespace pst

